diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java index 7069f5f8cec..93be4ca497b 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java @@ -49,6 +49,8 @@ import org.apache.log4j.spi.ThrowableRendererSupport; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.net.UrlConnectionFactory; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.util.StackLocatorUtil; /** @@ -383,7 +385,10 @@ public void doConfigure(final URL url, final LoggerRepository loggerRepository) Configuration doConfigure(final URL url, final LoggerRepository loggerRepository, final ClassLoader classLoader) { LogLog.debug("Reading configuration from URL " + url); try { - final URLConnection urlConnection = UrlConnectionFactory.createConnection(url); + // TODO: find better place to anchor Injector creation + final Injector injector = DI.createInjector(); + injector.init(); + final URLConnection urlConnection = injector.getInstance(UrlConnectionFactory.class).openConnection(url); try (InputStream inputStream = urlConnection.getInputStream()) { return doConfigure(inputStream, loggerRepository, classLoader); } 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 23931b2ee65..2267b36a45c 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 @@ -16,8 +16,6 @@ */ package org.apache.log4j.bridge; -import java.io.Serializable; - import org.apache.log4j.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -76,7 +74,7 @@ public Adapter getAdapter() { public class Adapter extends AbstractAppender { - protected Adapter(final String name, final Filter filter, final Layout layout, + protected Adapter(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, final Property[] properties) { super(name, filter, layout, ignoreExceptions, properties); } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java index 600f69f6d0e..27d13fc5d3d 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.message.Message; diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java index 4c1ea384547..81d794c9f7b 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java @@ -16,6 +16,11 @@ */ package org.apache.log4j.builders.appender; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import org.apache.log4j.Appender; import org.apache.log4j.Layout; import org.apache.log4j.bridge.AppenderWrapper; @@ -38,11 +43,6 @@ import org.apache.logging.log4j.status.StatusLogger; import org.w3c.dom.Element; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - import static org.apache.log4j.builders.BuilderManager.NAMESPACE; import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM; import static org.apache.log4j.xml.XmlConfiguration.*; @@ -115,7 +115,7 @@ public Appender parseAppender(final Element appenderElement, final XmlConfigurat }); return createAppender(name, layout.get(), filter.get(), fileName.get(), append.get(), immediateFlush.get(), level.get(), bufferedIo.get(), bufferSize.get(), datePattern.get(), config, - config.getComponent(Clock.KEY)); + config.getInstance(Clock.class)); } @Override @@ -131,7 +131,7 @@ public Appender parseAppender(final String name, final String appenderPrefix, fi final int bufferSize = getIntegerProperty(BUFFER_SIZE_PARAM, 8192); final String datePattern = getProperty(DATE_PATTERN_PARAM, DEFAULT_DATE_PATTERN); return createAppender(name, layout, filter, fileName, append, immediateFlush, level, bufferedIo, bufferSize, - datePattern, configuration, configuration.getComponent(Clock.KEY)); + datePattern, configuration, configuration.getInstance(Clock.class)); } private Appender createAppender(final String name, final Layout layout, diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java index 169191aa061..1323255f1cb 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java @@ -16,6 +16,11 @@ */ package org.apache.log4j.builders.appender; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import org.apache.log4j.Appender; import org.apache.log4j.Layout; import org.apache.log4j.bridge.AppenderWrapper; @@ -39,11 +44,6 @@ import org.apache.logging.log4j.status.StatusLogger; import org.w3c.dom.Element; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - import static org.apache.log4j.builders.BuilderManager.NAMESPACE; import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM; import static org.apache.log4j.xml.XmlConfiguration.*; @@ -120,7 +120,7 @@ public Appender parseAppender(final Element appenderElement, final XmlConfigurat }); return createAppender(name, config, layout.get(), filter.get(), append.get(), bufferedIo.get(), bufferSize.get(), immediateFlush.get(), fileName.get(), level.get(), maxSize.get(), maxBackups.get(), - config.getComponent(Clock.KEY)); + config.getInstance(Clock.class)); } @Override @@ -137,7 +137,7 @@ public Appender parseAppender(final String name, final String appenderPrefix, fi final String maxSize = getProperty(MAX_SIZE_PARAM, DEFAULT_MAX_SIZE); final String maxBackups = getProperty(MAX_BACKUP_INDEX, DEFAULT_MAX_BACKUPS); return createAppender(name, configuration, layout, filter, append, bufferedIo, bufferSize, immediateFlush, - fileName, level, maxSize, maxBackups, configuration.getComponent(Clock.KEY)); + fileName, level, maxSize, maxBackups, configuration.getInstance(Clock.class)); } private Appender createAppender(final String name, final Log4j1Configuration config, final Layout layout, diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java index 2e215e51055..24a408114e6 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java @@ -16,6 +16,11 @@ */ package org.apache.log4j.builders.appender; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import org.apache.log4j.Appender; import org.apache.log4j.Layout; import org.apache.log4j.bridge.AppenderWrapper; @@ -36,12 +41,6 @@ import org.apache.logging.log4j.util.Strings; import org.w3c.dom.Element; -import java.io.Serializable; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - import static org.apache.log4j.builders.BuilderManager.NAMESPACE; import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM; import static org.apache.log4j.xml.XmlConfiguration.*; @@ -141,7 +140,7 @@ private Appender createAppender(final String name, final Log4j1Configuration con final AtomicReference host = new AtomicReference<>(); final AtomicInteger port = new AtomicInteger(); resolveSyslogHost(syslogHost, host, port); - final org.apache.logging.log4j.core.Layout messageLayout = LayoutAdapter.adapt(layout); + final org.apache.logging.log4j.core.Layout messageLayout = LayoutAdapter.adapt(layout); final Log4j1SyslogLayout appenderLayout = Log4j1SyslogLayout.newBuilder() .setHeader(header) .setFacility(Facility.toFacility(facility)) diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java index 256f8170c47..b9680a9ad59 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java @@ -29,7 +29,7 @@ */ public class Log4j1Configuration extends AbstractConfiguration implements Reconfigurable { - public static final String MONITOR_INTERVAL = "log4j1.monitorInterval"; + public static final String MONITOR_INTERVAL = "log4j2.*.V1Compatibility.monitorInterval"; public static final String APPENDER_REF_TAG = "appender-ref"; public static final String THRESHOLD_PARAM = "Threshold"; diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java index 7edee3d86b8..fb3426839c2 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java @@ -368,7 +368,12 @@ private void parseLoggers(final Properties props) { LoggerConfig loggerConfig = getLogger(loggerName); if (loggerConfig == null) { final boolean additivity = getAdditivityForLogger(props, loggerName); - loggerConfig = new LoggerConfig(loggerName, org.apache.logging.log4j.Level.ERROR, additivity); + loggerConfig = LoggerConfig.newBuilder() + .setLoggerName(loggerName) + .setLevel(org.apache.logging.log4j.Level.ERROR) + .setAdditivity(additivity) + .setConfig(this) + .get(); addLogger(loggerName, loggerConfig); } parseLogger(props, loggerConfig, key, loggerName, value); diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java index bf8f1cab2eb..03ef4eb69bd 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java @@ -23,7 +23,7 @@ import org.apache.logging.log4j.core.config.Order; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; /** * Configures Log4j from a log4j 1 format properties file. @@ -47,7 +47,7 @@ public class PropertiesConfigurationFactory extends ConfigurationFactory { @Override protected String[] getSupportedTypes() { - if (!PropertiesUtil.getProperties().getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, Boolean.FALSE)) { + if (!propertyResolver.getBoolean(ConfigurationFactory.LOG4J1_EXPERIMENTAL)) { return null; } return new String[] { FILE_EXTENSION }; @@ -55,7 +55,8 @@ protected String[] getSupportedTypes() { @Override public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) { - int interval = PropertiesUtil.getProperties().getIntegerProperty(Log4j1Configuration.MONITOR_INTERVAL, 0); + final PropertyResolver propertyResolver = loggerContext != null ? loggerContext.getPropertyResolver() : this.propertyResolver; + int interval = propertyResolver.getInt(Log4j1Configuration.MONITOR_INTERVAL).orElse(0); return new PropertiesConfiguration(loggerContext, source, interval); } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java index 1a504492b5a..bb314fd84fd 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java @@ -16,7 +16,6 @@ */ package org.apache.log4j.layout; -import java.io.Serializable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.HashMap; @@ -76,7 +75,7 @@ public Builder() { private boolean header; @PluginElement("Layout") - private Layout messageLayout; + private Layout messageLayout; @Override public Log4j1SyslogLayout build() { @@ -99,7 +98,7 @@ public boolean isHeader() { return header; } - public Layout getMessageLayout() { + public Layout getMessageLayout() { return messageLayout; } @@ -118,7 +117,7 @@ public B setHeader(final boolean header) { return asBuilder(); } - public B setMessageLayout(final Layout messageLayout) { + public B setMessageLayout(final Layout messageLayout) { this.messageLayout = messageLayout; return asBuilder(); } @@ -192,7 +191,9 @@ public String toSerializable(final LogEvent event) { buf.append(message); // TODO: splitting message into 1024 byte chunks? - return buf.toString(); + final String result = buf.toString(); + recycleStringBuilder(buf); + return result; } /** diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java index 4eb629c62a7..f10da8fead6 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java @@ -78,13 +78,16 @@ public void encode(final LogEvent event, final ByteBufferDestination destination final StringBuilder text = getStringBuilder(); formatTo(event, text); getStringBuilderEncoder().encode(text, destination); + recycleStringBuilder(text); } @Override public String toSerializable(final LogEvent event) { final StringBuilder text = getStringBuilder(); formatTo(event, text); - return text.toString(); + final String result = text.toString(); + recycleStringBuilder(text); + return result; } private void formatTo(final LogEvent event, final StringBuilder buf) { diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java index f16ed3803bd..fe346922029 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java @@ -24,10 +24,10 @@ import org.apache.log4j.spi.LocationInfo; import org.apache.log4j.spi.LoggingEvent; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.Cast; import org.apache.logging.log4j.util.SortedArrayStringMap; /** @@ -54,10 +54,9 @@ public class MapRewritePolicy implements RewritePolicy { public LoggingEvent rewrite(final LoggingEvent source) { Object msg = source.getMessage(); if (msg instanceof MapMessage || msg instanceof Map) { - Map props = source.getProperties() != null ? new HashMap<>(source.getProperties()) + Map props = source.getProperties() != null ? new HashMap<>(Cast.cast(source.getProperties())) : new HashMap<>(); - @SuppressWarnings("unchecked") - Map eventProps = msg instanceof Map ? (Map) msg : ((MapMessage) msg).getData(); + Map eventProps = Cast.cast(msg instanceof Map ? msg : ((MapMessage) msg).getData()); // // if the map sent in the logging request // has "message" entry, use that as the message body @@ -78,10 +77,10 @@ public LoggingEvent rewrite(final LoggingEvent source) { LogEvent event; if (source instanceof LogEventAdapter) { - event = new Log4jLogEvent.Builder(((LogEventAdapter) source).getEvent()) + event = LogEvent.builderFrom(((LogEventAdapter) source).getEvent()) .setMessage(newMessage) .setContextData(new SortedArrayStringMap(props)) - .build(); + .toImmutable(); } else { LocationInfo info = source.getLocationInformation(); StackTraceElement element = new StackTraceElement(info.getClassName(), info.getMethodName(), @@ -89,11 +88,10 @@ public LoggingEvent rewrite(final LoggingEvent source) { Thread thread = getThread(source.getThreadName()); long threadId = thread != null ? thread.getId() : 0; int threadPriority = thread != null ? thread.getPriority() : 0; - event = Log4jLogEvent.newBuilder() + event = LogEvent.builder() .setContextData(new SortedArrayStringMap(props)) .setLevel(OptionConverter.convertLevel(source.getLevel())) .setLoggerFqcn(source.getFQNOfLoggerClass()) - .setMarker(null) .setMessage(newMessage) .setSource(element) .setLoggerName(source.getLoggerName()) @@ -102,9 +100,7 @@ public LoggingEvent rewrite(final LoggingEvent source) { .setThreadPriority(threadPriority) .setThrown(source.getThrowableInformation().getThrowable()) .setTimeMillis(source.getTimeStamp()) - .setNanoTime(0) - .setThrownProxy(null) - .build(); + .toImmutable(); } return new LogEventAdapter(event); } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java index a84deacb4d6..1373d2af8d2 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java @@ -16,7 +16,6 @@ */ package org.apache.log4j.rewrite; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; @@ -26,8 +25,8 @@ import org.apache.log4j.spi.LocationInfo; import org.apache.log4j.spi.LoggingEvent; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.Cast; import org.apache.logging.log4j.util.SortedArrayStringMap; /** @@ -40,7 +39,7 @@ *

*/ public class PropertyRewritePolicy implements RewritePolicy { - private Map properties = Collections.EMPTY_MAP; + private Map properties = Map.of(); public PropertyRewritePolicy() { } @@ -74,7 +73,8 @@ public void setProperties(String properties) { @Override public LoggingEvent rewrite(final LoggingEvent source) { if (!properties.isEmpty()) { - Map rewriteProps = source.getProperties() != null ? new HashMap<>(source.getProperties()) + Map rewriteProps = source.getProperties() != null + ? new HashMap<>(Cast.cast(source.getProperties())) : new HashMap<>(); for (Map.Entry entry : properties.entrySet()) { if (!rewriteProps.containsKey(entry.getKey())) { @@ -83,9 +83,9 @@ public LoggingEvent rewrite(final LoggingEvent source) { } LogEvent event; if (source instanceof LogEventAdapter) { - event = new Log4jLogEvent.Builder(((LogEventAdapter) source).getEvent()) + event = LogEvent.builderFrom(((LogEventAdapter) source).getEvent()) .setContextData(new SortedArrayStringMap(rewriteProps)) - .build(); + .toImmutable(); } else { LocationInfo info = source.getLocationInformation(); StackTraceElement element = new StackTraceElement(info.getClassName(), info.getMethodName(), @@ -93,11 +93,10 @@ public LoggingEvent rewrite(final LoggingEvent source) { Thread thread = getThread(source.getThreadName()); long threadId = thread != null ? thread.getId() : 0; int threadPriority = thread != null ? thread.getPriority() : 0; - event = Log4jLogEvent.newBuilder() + event = LogEvent.builder() .setContextData(new SortedArrayStringMap(rewriteProps)) .setLevel(OptionConverter.convertLevel(source.getLevel())) .setLoggerFqcn(source.getFQNOfLoggerClass()) - .setMarker(null) .setMessage(new SimpleMessage(source.getRenderedMessage())) .setSource(element) .setLoggerName(source.getLoggerName()) @@ -106,9 +105,7 @@ public LoggingEvent rewrite(final LoggingEvent source) { .setThreadPriority(threadPriority) .setThrown(source.getThrowableInformation().getThrowable()) .setTimeMillis(source.getTimeStamp()) - .setNanoTime(0) - .setThrownProxy(null) - .build(); + .toImmutable(); } return new LogEventAdapter(event); } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/DOMConfigurator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/DOMConfigurator.java index b0cbb582b1f..5599fe3f7ac 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/DOMConfigurator.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/DOMConfigurator.java @@ -28,7 +28,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Properties; - import javax.xml.parsers.FactoryConfigurationError; import org.apache.log4j.LogManager; @@ -41,6 +40,8 @@ import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.net.UrlConnectionFactory; import org.apache.logging.log4j.core.util.IOUtils; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.w3c.dom.Element; /** @@ -145,7 +146,10 @@ public void doConfigure(final String fileName, final LoggerRepository repository public void doConfigure(final URL url, final LoggerRepository repository) { try { - final URLConnection connection = UrlConnectionFactory.createConnection(url); + // TODO: find better place to anchor Injector creation + final Injector injector = DI.createInjector(); + injector.init(); + final URLConnection connection = injector.getInstance(UrlConnectionFactory.class).openConnection(url); try (InputStream inputStream = connection.getInputStream()) { doConfigure(new ConfigurationSource(inputStream, url)); } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java index 07eb38db8a9..db13576d9a4 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java @@ -560,7 +560,12 @@ private void parseCategory(Element loggerElement) { boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true); LoggerConfig loggerConfig = getLogger(catName); if (loggerConfig == null) { - loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity); + loggerConfig = LoggerConfig.newBuilder() + .setLoggerName(catName) + .setLevel(org.apache.logging.log4j.Level.ERROR) + .setAdditivity(additivity) + .setConfig(this) + .get(); addLogger(catName, loggerConfig); } else { loggerConfig.setAdditive(additivity); diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java index 4d7e315268e..49213ada080 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java @@ -16,13 +16,6 @@ */ package org.apache.log4j.config; -import static org.junit.Assert.fail; -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.assertTrue; - -import java.io.Serializable; import java.net.URISyntaxException; import java.net.URL; @@ -40,6 +33,9 @@ import org.apache.logging.log4j.core.layout.PatternLayout; import org.junit.Test; +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.*; + public class Log4j1ConfigurationFactoryTest extends AbstractLog4j1ConfigurationTest { private static final String SUFFIX = ".properties"; @@ -166,7 +162,7 @@ public void testUntrimmedValues() throws Exception { assertEquals(Level.DEBUG, rootLogger.getLevel()); final Appender appender = config.getAppender("Console"); assertTrue(appender instanceof ConsoleAppender); - final Layout layout = appender.getLayout(); + final Layout layout = appender.getLayout(); assertTrue(layout instanceof PatternLayout); assertEquals("%v1Level - %m%n", ((PatternLayout)layout).getConversionPattern()); // No filter support diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java index bf4705e9d3f..a3c6f9f20fb 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java @@ -16,15 +16,9 @@ */ package org.apache.log4j.config; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.Serializable; import java.net.URISyntaxException; import java.nio.file.Path; import java.util.List; @@ -54,6 +48,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import static org.junit.jupiter.api.Assertions.*; + /** * Test configuration from Properties. */ @@ -299,7 +295,7 @@ public void testUntrimmedValues() throws Exception { assertEquals(Level.DEBUG, rootLogger.getLevel()); final Appender appender = config.getAppender("Console"); assertTrue(appender instanceof ConsoleAppender); - final Layout layout = appender.getLayout(); + final Layout layout = appender.getLayout(); assertTrue(layout instanceof PatternLayout); assertEquals("%v1Level - %m%n", ((PatternLayout)layout).getConversionPattern()); final Filter filter = ((Filterable) appender).getFilter(); diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java index 1c2cf7130b6..5b584c89ddc 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java @@ -16,17 +16,17 @@ */ package org.apache.log4j.layout; -import static org.junit.Assert.assertEquals; - import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.test.junit.ThreadContextRule; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.test.junit.ThreadContextRule; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.junit.Rule; import org.junit.Test; +import static org.junit.Assert.assertEquals; + public class Log4j1XmlLayoutTest { @Rule @@ -36,7 +36,7 @@ public class Log4j1XmlLayoutTest { public void testWithoutThrown() { final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(false, true); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("a.B") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, World")) @@ -57,15 +57,15 @@ public void testWithoutThrown() { public void testWithPropertiesAndLocationInfo() { final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(true, true); - final StringMap contextMap = ContextDataFactory.createContextData(2); + final StringMap contextMap = new SortedArrayStringMap(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("a.B") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, World")) .setTimeMillis(System.currentTimeMillis() + 17) - .setIncludeLocation(true) + .includeLocation(true) .setSource(new StackTraceElement("pack.MyClass", "myMethod", "MyClass.java", 17)) .setContextData(contextMap) .build(); diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java index c1d5b83254b..7a99bccef41 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java @@ -16,28 +16,27 @@ */ package org.apache.log4j.pattern; -import static org.junit.Assert.assertEquals; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class Log4j1MdcPatternConverterTest { @Test public void testConverter0() { - final StringMap contextMap = ContextDataFactory.createContextData(0); + final StringMap contextMap = new SortedArrayStringMap(0); final String expected = "{}"; test(contextMap, expected, null); } @Test public void testConverter1() { - final StringMap contextMap = ContextDataFactory.createContextData(1); + final StringMap contextMap = new SortedArrayStringMap(1); contextMap.putValue("key1", "value1"); final String expected = "{{key1,value1}}"; test(contextMap, expected, null); @@ -45,7 +44,7 @@ public void testConverter1() { @Test public void testConverter2() { - final StringMap contextMap = ContextDataFactory.createContextData(2); + final StringMap contextMap = new SortedArrayStringMap(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); final String expected = "{{key1,value1}{key2,value2}}"; @@ -54,7 +53,7 @@ public void testConverter2() { @Test public void testConverterWithKey() { - final StringMap contextMap = ContextDataFactory.createContextData(2); + final StringMap contextMap = new SortedArrayStringMap(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); final String expected = "value1"; @@ -62,12 +61,12 @@ public void testConverterWithKey() { } private void test(final StringMap contextMap, final String expected, final String[] options) { - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("MyLogger") .setLevel(Level.DEBUG) .setMessage(new SimpleMessage("Hello")) .setContextData(contextMap) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final Log4j1MdcPatternConverter converter = Log4j1MdcPatternConverter.newInstance(options); converter.format(event, sb); diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java index 170e7bf68f3..53587fd6bdd 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java @@ -16,17 +16,16 @@ */ package org.apache.log4j.pattern; -import static org.junit.Assert.assertEquals; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.test.junit.ThreadContextStackRule; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.test.junit.ThreadContextStackRule; import org.junit.Rule; import org.junit.Test; +import static org.junit.Assert.assertEquals; + public class Log4j1NdcPatternConverterTest { @Rule @@ -60,11 +59,11 @@ public void test3() { private void testConverter(final String expected) { final Log4j1NdcPatternConverter converter = Log4j1NdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("MyLogger") .setLevel(Level.DEBUG) .setMessage(new SimpleMessage("Hello")) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals(expected, sb.toString()); diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/ThreadContextUtilityClass.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/ThreadContextUtilityClass.java index d39dbdc4406..519f33e1915 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/ThreadContextUtilityClass.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/ThreadContextUtilityClass.java @@ -21,12 +21,7 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.util.Timer; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class ThreadContextUtilityClass { @@ -118,7 +113,4 @@ public static void testPut() { assertEquals("testValue", ThreadContext.get("testKey")); } - public static void reset() { - ThreadContext.init(); - } } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ThreadContextInitializer.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ThreadContextInitializer.java index c246c3ce5fc..b3c40673df7 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ThreadContextInitializer.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ThreadContextInitializer.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.test.junit; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.test.ThreadContextUtilityClass; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; @@ -42,14 +41,14 @@ public void beforeEach(ExtensionContext context) throws Exception { } private void resetThreadContext(ExtensionContext context) { - ThreadContextUtilityClass.reset(); + ThreadContext.init(); // We use `CloseableResource` instead of `afterAll` to reset the // ThreadContextFactory // *after* the `@SetSystemProperty` extension has restored the properties ExtensionContextAnchor.setAttribute(ThreadContext.class, new CloseableResource() { @Override public void close() throws Throwable { - ThreadContextUtilityClass.reset(); + ThreadContext.init(); } }, context); diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/NoopThreadContextTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/NoopThreadContextTest.java index a93a7cbc30a..2032da9fa5c 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/NoopThreadContextTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/NoopThreadContextTest.java @@ -30,8 +30,8 @@ public class NoopThreadContextTest { @Test - @SetSystemProperty(key = LoggingSystemProperties.THREAD_CONTEXT_DISABLED, value = "true") - @SetSystemProperty(key = LoggingSystemProperties.THREAD_CONTEXT_MAP_DISABLED, value = "true") + @SetSystemProperty(key = LoggingSystemProperties.THREAD_CONTEXT_ENABLED, value = "false") + @SetSystemProperty(key = LoggingSystemProperties.THREAD_CONTEXT_MAP_ENABLED, value = "false") @InitializesThreadContext @UsingThreadContextMap public void testNoop() { diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/DefaultPropertyResolverTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/DefaultPropertyResolverTest.java new file mode 100644 index 00000000000..2506bec9c02 --- /dev/null +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/DefaultPropertyResolverTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.net.URL; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DefaultPropertyResolverTest { + final PropertyResolver resolver = new DefaultPropertyResolver(); + + @BeforeEach + void setUp() { + final URL json = getClass().getClassLoader().getResource("property-resolver-test.json"); + assertNotNull(json); + resolver.addSource(JsonResourcePropertySource.fromUrl(json, 0)); + // TODO: test properties file version too + } + + @Test + void hasProperty() { + assertTrue(resolver.hasProperty("log4j2.*.Component1.propertyName1")); + assertTrue(resolver.hasProperty("TestContext", "log4j2.*.Component1.propertyName1")); + assertTrue(resolver.hasProperty("log4j2.*.Component1.propertyName2")); + assertTrue(resolver.hasProperty("TestContext", "log4j2.*.Component2.propertyName5")); + assertFalse(resolver.hasProperty("log4j2.*.Component1.propertyName5")); + } + + @Test + void getString() { + assertEquals("value1", resolver.getString("log4j2.*.Component1.propertyName1").orElseThrow()); + assertEquals("override", resolver.getString("TestContext", "log4j2.*.Component1.propertyName1").orElseThrow()); + } + + @Test + void getList() { + final List list = resolver.getList("log4j2.*.Component2.propertyName6"); + assertEquals(List.of("foo", "bar"), list); + } + + @Test + void getBoolean() { + assertTrue(resolver.getBoolean("log4j2.*.Component1.propertyName4")); + } + + @Test + void getInt() { + assertEquals(3, resolver.getInt("log4j2.*.Component1.propertyName3").orElseThrow()); + } + + @Test + void getLong() { + assertEquals(90000L, resolver.getLong("log4j2.*.Component2.propertyName5").orElseThrow()); + assertEquals(0L, resolver.getLong("TestContext", "log4j2.*.Component2.propertyName5").orElseThrow()); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/JsonReaderTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/JsonReaderTest.java similarity index 99% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/JsonReaderTest.java rename to log4j-api-test/src/test/java/org/apache/logging/log4j/util/JsonReaderTest.java index 5da282052db..139295f06eb 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/JsonReaderTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/JsonReaderTest.java @@ -14,12 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +package org.apache.logging.log4j.util; import java.math.BigDecimal; import java.math.BigInteger; @@ -28,6 +23,11 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + class JsonReaderTest { @Test diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java index 13700572d3a..2e76d3e89c4 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java @@ -20,19 +20,24 @@ import java.util.Collections; import java.util.Enumeration; +import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearSystemProperty; import org.junitpioneer.jupiter.ReadsSystemProperty; +import org.junitpioneer.jupiter.WritesSystemProperty; import static org.junit.jupiter.api.Assertions.assertEquals; @ReadsSystemProperty +@WritesSystemProperty +@ClearSystemProperty(key = LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER) public class LoaderUtilTest { @BeforeEach @AfterEach public void reset() { - LoaderUtil.forceTcclOnly = null; + System.clearProperty(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER); } @Test @@ -40,7 +45,7 @@ public void systemClassLoader() { final Thread thread = Thread.currentThread(); final ClassLoader tccl = thread.getContextClassLoader(); - LoaderUtil.forceTcclOnly = true; + System.setProperty(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER, "true"); final ClassLoader loader = new ClassLoader(tccl) { @Override public Enumeration getResources(final String name) { @@ -51,7 +56,7 @@ public Enumeration getResources(final String name) { try { assertEquals(0, LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size()); - LoaderUtil.forceTcclOnly = false; + System.setProperty(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER, "false"); assertEquals(1, LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size()); } finally { thread.setContextClassLoader(tccl); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParserTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java similarity index 96% rename from log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParserTest.java rename to log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java index f2790708d92..9e17e08e126 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParserTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java @@ -14,15 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; - -import org.apache.logging.log4j.layout.template.json.util.StringParameterParser.DoubleQuotedStringValue; -import org.apache.logging.log4j.layout.template.json.util.StringParameterParser.NullValue; -import org.apache.logging.log4j.layout.template.json.util.StringParameterParser.StringValue; -import org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Value; -import org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; +package org.apache.logging.log4j.util; import java.util.Collections; import java.util.LinkedHashMap; @@ -30,6 +22,15 @@ import java.util.Map; import java.util.Set; +import org.apache.logging.log4j.util.StringParameterParser; +import org.apache.logging.log4j.util.StringParameterParser.DoubleQuotedStringValue; +import org.apache.logging.log4j.util.StringParameterParser.NullValue; +import org.apache.logging.log4j.util.StringParameterParser.StringValue; +import org.apache.logging.log4j.util.StringParameterParser.Value; +import org.apache.logging.log4j.util.StringParameterParser.Values; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + @SuppressWarnings("DoubleBraceInitialization") class StringParameterParserTest { diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ThreadLocalRecyclerTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ThreadLocalRecyclerTest.java new file mode 100644 index 00000000000..a332158e5f8 --- /dev/null +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ThreadLocalRecyclerTest.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class ThreadLocalRecyclerTest { + + @Test + void referenceCountingEnabledTracking() { + final ThreadLocalRecycler recycler = + new ThreadLocalRecycler<>(AtomicInteger::new, i -> i.set(0), true); + + assertThat(recycler.getActiveReferenceCount()).isEqualTo(0); + final AtomicInteger first = recycler.acquire(); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(1); + final AtomicInteger second = recycler.acquire(); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(2); + first.set(1); + second.set(2); + final AtomicInteger third = recycler.acquire(); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(3); + assertThat(third.get()).isEqualTo(0); + assertThat(first.get()).isEqualTo(1); + assertThat(second.get()).isEqualTo(2); + recycler.release(first); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(2); + recycler.release(second); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(1); + recycler.release(third); + assertThat(recycler.getActiveReferenceCount()).isEqualTo(0); + } +} diff --git a/log4j-api-test/src/test/resources/property-resolver-test.json b/log4j-api-test/src/test/resources/property-resolver-test.json new file mode 100644 index 00000000000..3290f39569c --- /dev/null +++ b/log4j-api-test/src/test/resources/property-resolver-test.json @@ -0,0 +1,22 @@ +{"log4j2": { + "*": { + "Component1": { + "propertyName1": "value1", + "propertyName2": "value2", + "propertyName3": 3, + "propertyName4": true + }, + "Component2": { + "propertyName5": 90000, + "propertyName6": ["foo", "bar"] + } + }, + "TestContext": { + "Component1": { + "propertyName1": "override" + }, + "Component2": { + "propertyName5": 0 + } + } +}} diff --git a/log4j-api-test/src/test/resources/property-resolver-test.properties b/log4j-api-test/src/test/resources/property-resolver-test.properties new file mode 100644 index 00000000000..d7befce6744 --- /dev/null +++ b/log4j-api-test/src/test/resources/property-resolver-test.properties @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache license, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the license for the specific language governing permissions and +# limitations under the license. +# + +log4j2.*.Component1.propertyName1 = value1 +log4j2.*.Component1.propertyName2 = value2 +log4j2.*.Component1.propertyName3 = 3 +log4j2.*.Component1.propertyName4 = true +log4j2.*.Component2.propertyName5 = 90000 +log4j2.*.Component2.propertyName6 = foo, bar +log4j2.TestContext.Component1.propertyName1 = override +log4j2.TestContext.Component2.propertyName5 = 0 diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 714dea6c2b0..c83b0de9df5 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -43,6 +43,11 @@ org.osgi.resource provided + + org.jctools + jctools-core + true + @@ -52,10 +57,6 @@ org.apache.logging.log4j.* - - sun.reflect;resolution:=optional, - * - org.apache.logging.log4j.util.Activator <_fixupmessages>"Classes found in the wrong directory";is:=warning diff --git a/log4j-api/src/main/java/module-info.java b/log4j-api/src/main/java/module-info.java index 57f500e63e1..f1b38be8bbf 100644 --- a/log4j-api/src/main/java/module-info.java +++ b/log4j-api/src/main/java/module-info.java @@ -40,6 +40,7 @@ requires static java.sql; requires static org.osgi.framework; + requires static org.jctools.core; uses org.apache.logging.log4j.spi.Provider; uses PropertySource; uses org.apache.logging.log4j.message.ThreadDumpMessage.ThreadInfoFactory; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java index 1f8dec7827b..9e66a1d3775 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java @@ -364,7 +364,7 @@ public static void shutdown(final LoggerContext context) { * @return The LoggerContextFactory. */ public static LoggerContextFactory getFactory() { - return LoggingSystem.getLoggerContextFactory(); + return LoggingSystem.loggerContextFactory(); } /** diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java index 2b2b30c05ab..783a46f456b 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java @@ -20,6 +20,7 @@ import org.apache.logging.log4j.message.FlowMessageFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.util.MessageSupplier; import org.apache.logging.log4j.util.Supplier; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java index 5711276ef52..6277949c7b6 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java @@ -17,13 +17,14 @@ package org.apache.logging.log4j; import java.io.Serializable; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.AbstractCollection; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.spi.DefaultThreadContextMap; @@ -33,6 +34,7 @@ import org.apache.logging.log4j.spi.ThreadContextMap; import org.apache.logging.log4j.spi.ThreadContextStack; import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.InternalException; /** * The ThreadContext allows applications to store information either in a Map or a Stack. @@ -52,8 +54,6 @@ private static class EmptyThreadContextStack extends AbstractCollection private static final long serialVersionUID = 1L; - private static final Iterator EMPTY_ITERATOR = new EmptyIterator<>(); - @Override public String pop() { return null; @@ -133,7 +133,7 @@ public boolean retainAll(final Collection c) { @Override public Iterator iterator() { - return EMPTY_ITERATOR; + return Collections.emptyIterator(); } @Override @@ -147,29 +147,6 @@ public ContextStack getImmutableStackOrNull() { } } - /** - * An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do. - * - * @param the type of the empty iterator - */ - private static class EmptyIterator implements Iterator { - - @Override - public boolean hasNext() { - return false; - } - - @Override - public E next() { - throw new NoSuchElementException("This is an empty iterator!"); - } - - @Override - public void remove() { - // no-op - } - } - /** * Empty, immutable Map. */ @@ -185,16 +162,34 @@ public void remove() { @SuppressWarnings("PublicStaticCollectionField") public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack(); - private static ThreadContextMap contextMap; - private static ThreadContextStack contextStack; - private static ReadOnlyThreadContextMap readOnlyContextMap; + private static volatile ThreadContext instance; + private static final VarHandle INSTANCE; static { - init(); + try { + INSTANCE = MethodHandles.lookup() + .findStaticVarHandle(ThreadContext.class, "instance", ThreadContext.class); + } catch (final NoSuchFieldException | IllegalAccessException e) { + throw new InternalException(e); + } } + private final ThreadContextMap map = LoggingSystem.createContextMap(); + private final ThreadContextStack stack = LoggingSystem.createContextStack(); + private final ReadOnlyThreadContextMap readOnlyMap; + private ThreadContext() { - // empty + readOnlyMap = map instanceof ReadOnlyThreadContextMap ? (ReadOnlyThreadContextMap) map : null; + } + + private static ThreadContext getInstance() { + ThreadContext context = (ThreadContext) INSTANCE.getAcquire(); + if (context != null) { + return context; + } + final ThreadContext newContext = new ThreadContext(); + final ThreadContext witness = (ThreadContext) INSTANCE.compareAndExchangeRelease(null, newContext); + return witness == null ? newContext : witness; } /** @@ -202,13 +197,8 @@ private ThreadContext() { */ @InternalApi public static void init() { - contextMap = LoggingSystem.createContextMap(); - contextStack = LoggingSystem.createContextStack(); - if (contextMap instanceof ReadOnlyThreadContextMap) { - readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap; - } else { - readOnlyContextMap = null; - } + final ThreadContext context = new ThreadContext(); + INSTANCE.setRelease(context); } /** @@ -223,7 +213,7 @@ public static void init() { * @param value The key value. */ public static void put(final String key, final String value) { - contextMap.put(key, value); + getInstance().map.put(key, value); } /** @@ -239,8 +229,9 @@ public static void put(final String key, final String value) { * @since 2.13.0 */ public static void putIfNull(final String key, final String value) { - if(!contextMap.containsKey(key)) { - contextMap.put(key, value); + final ThreadContextMap map = getInstance().map; + if (!map.containsKey(key)) { + map.put(key, value); } } @@ -254,7 +245,7 @@ public static void putIfNull(final String key, final String value) { * @since 2.7 */ public static void putAll(final Map m) { - contextMap.putAll(m); + getInstance().map.putAll(m); } /** @@ -268,7 +259,7 @@ public static void putAll(final Map m) { * @return The value associated with the key or null. */ public static String get(final String key) { - return contextMap.get(key); + return getInstance().map.get(key); } /** @@ -277,7 +268,7 @@ public static String get(final String key) { * @param key The key to remove. */ public static void remove(final String key) { - contextMap.remove(key); + getInstance().map.remove(key); } /** @@ -288,22 +279,23 @@ public static void remove(final String key) { * @since 2.8 */ public static void removeAll(final Iterable keys) { - contextMap.removeAll(keys); + getInstance().map.removeAll(keys); } /** * Clears the context map. */ public static void clearMap() { - contextMap.clear(); + getInstance().map.clear(); } /** * Clears the context map and stack. */ public static void clearAll() { - clearMap(); - clearStack(); + final ThreadContext context = getInstance(); + context.map.clear(); + context.stack.clear(); } /** @@ -313,7 +305,7 @@ public static void clearAll() { * @return True if the key is in the context, false otherwise. */ public static boolean containsKey(final String key) { - return contextMap.containsKey(key); + return getInstance().map.containsKey(key); } /** @@ -322,7 +314,7 @@ public static boolean containsKey(final String key) { * @return a mutable copy of the context. */ public static Map getContext() { - return contextMap.getCopy(); + return getInstance().map.getCopy(); } /** @@ -331,7 +323,7 @@ public static Map getContext() { * @return An immutable view of the ThreadContext Map. */ public static Map getImmutableContext() { - final Map map = contextMap.getImmutableMapOrNull(); + final Map map = getInstance().map.getImmutableMapOrNull(); return map == null ? EMPTY_MAP : map; } @@ -351,7 +343,7 @@ public static Map getImmutableContext() { * @since 2.8 */ public static ReadOnlyThreadContextMap getThreadContextMap() { - return readOnlyContextMap; + return getInstance().readOnlyMap; } /** @@ -360,14 +352,14 @@ public static ReadOnlyThreadContextMap getThreadContextMap() { * @return true if the Map is empty, false otherwise. */ public static boolean isEmpty() { - return contextMap.isEmpty(); + return getInstance().map.isEmpty(); } /** * Clears the stack for this thread. */ public static void clearStack() { - contextStack.clear(); + getInstance().stack.clear(); } /** @@ -376,7 +368,7 @@ public static void clearStack() { * @return A copy of this thread's stack. */ public static ContextStack cloneStack() { - return contextStack.copy(); + return getInstance().stack.copy(); } /** @@ -385,7 +377,7 @@ public static ContextStack cloneStack() { * @return an immutable copy of the ThreadContext stack. */ public static ContextStack getImmutableStack() { - final ContextStack result = contextStack.getImmutableStackOrNull(); + final ContextStack result = getInstance().stack.getImmutableStackOrNull(); return result == null ? EMPTY_STACK : result; } @@ -398,6 +390,7 @@ public static void setStack(final Collection stack) { if (stack.isEmpty()) { return; } + final ThreadContextStack contextStack = getInstance().stack; contextStack.clear(); contextStack.addAll(stack); } @@ -410,7 +403,7 @@ public static void setStack(final Collection stack) { * @see #trim */ public static int getDepth() { - return contextStack.getDepth(); + return getInstance().stack.getDepth(); } /** @@ -424,7 +417,7 @@ public static int getDepth() { * @return String The innermost diagnostic context. */ public static String pop() { - return contextStack.pop(); + return getInstance().stack.pop(); } /** @@ -438,7 +431,7 @@ public static String pop() { * @return String The innermost diagnostic context. */ public static String peek() { - return contextStack.peek(); + return getInstance().stack.peek(); } /** @@ -451,7 +444,7 @@ public static String peek() { * @param message The new diagnostic context information. */ public static void push(final String message) { - contextStack.push(message); + getInstance().stack.push(message); } /** @@ -467,7 +460,7 @@ public static void push(final String message) { * @param args Parameters for the message. */ public static void push(final String message, final Object... args) { - contextStack.push(ParameterizedMessage.format(message, args)); + getInstance().stack.push(ParameterizedMessage.format(message, args)); } /** @@ -487,7 +480,7 @@ public static void push(final String message, final Object... args) { *

*/ public static void removeStack() { - contextStack.clear(); + getInstance().stack.clear(); } /** @@ -523,7 +516,7 @@ public static void removeStack() { * @param depth The number of elements to keep. */ public static void trim(final int depth) { - contextStack.trim(depth); + getInstance().stack.trim(depth); } /** diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessageJsonFormatter.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessageJsonFormatter.java index 89b840a34ed..54c7b8bc1d5 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessageJsonFormatter.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessageJsonFormatter.java @@ -22,9 +22,9 @@ import java.util.Map; import java.util.Set; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.util.IndexedStringMap; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.StringBuilderFormattable; import org.apache.logging.log4j.util.StringBuilders; @@ -65,9 +65,9 @@ enum MapMessageJsonFormatter {; private static final char COLON = ':'; private static int readMaxDepth() { - final int maxDepth = PropertiesUtil - .getProperties() - .getIntegerProperty(LoggingSystemProperties.LOGGER_MAP_MESSAGE_JSON_FORMATTER_MAX_DEPTH, 8); + final int maxDepth = LoggingSystem.getPropertyResolver() + .getInt(LoggingSystemProperties.LOGGER_MAP_MESSAGE_JSON_FORMATTER_MAX_DEPTH) + .orElse(8); if (maxDepth < 0) { throw new IllegalArgumentException( "was expecting a positive maxDepth, found: " + maxDepth); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerConfiguration.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerConfiguration.java index 9e06cd0fce6..b1d0e335c7a 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerConfiguration.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerConfiguration.java @@ -20,27 +20,27 @@ import java.text.SimpleDateFormat; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.spi.LoggingSystemProperties; +import org.apache.logging.log4j.util.PropertyResolver; import static org.apache.logging.log4j.simple.SimpleLoggerContext.DEFAULT_DATE_TIME_FORMAT; -import static org.apache.logging.log4j.simple.SimpleLoggerContext.SYSTEM_PREFIX; public class SimpleLoggerConfiguration { - protected final PropertyEnvironment environment; + protected final PropertyResolver propertyResolver; - public SimpleLoggerConfiguration(final PropertyEnvironment environment) { - this.environment = environment; + public SimpleLoggerConfiguration(final PropertyResolver resolver) { + propertyResolver = resolver; } /** Include the ThreadContextMap in the log message */ public boolean isContextMapShown() { - return environment.getBooleanProperty(SYSTEM_PREFIX + "showContextMap", false); + return propertyResolver.getBoolean(LoggingSystemProperties.SIMPLE_SHOW_CONTEXT_MAP, false); } /** Include the instance name in the log message? */ public boolean isLogNameShown() { - return environment.getBooleanProperty(SYSTEM_PREFIX + "showlogname", false); + return propertyResolver.getBoolean(LoggingSystemProperties.SIMPLE_SHOW_LOG_NAME, false); } /** @@ -48,33 +48,39 @@ public boolean isLogNameShown() { * lost in a flood of messages without knowing who sends them. */ public boolean isShortNameShown() { - return environment.getBooleanProperty(SYSTEM_PREFIX + "showShortLogname", true); + return propertyResolver.getBoolean(LoggingSystemProperties.SIMPLE_SHOW_SHORT_LOG_NAME, true); } /** Include the current time in the log message */ public boolean isDateTimeShown() { - return environment.getBooleanProperty(SYSTEM_PREFIX + "showdatetime", false); + return propertyResolver.getBoolean(LoggingSystemProperties.SIMPLE_SHOW_DATE_TIME, false); } public Level getDefaultLevel() { - final String level = environment.getStringProperty(SYSTEM_PREFIX + "level"); - return Level.toLevel(level, Level.ERROR); + return propertyResolver.getString(LoggingSystemProperties.SIMPLE_LOG_LEVEL) + .map(Level::getLevel) + .orElse(Level.ERROR); } public Level getLoggerLevel(final String loggerName) { - final String level = environment.getStringProperty(SYSTEM_PREFIX + loggerName + ".level"); - return Level.toLevel(level, getDefaultLevel()); + return propertyResolver.getString(String.format(LoggingSystemProperties.SIMPLE_LOGGER_LOG_LEVEL, loggerName)) + .map(Level::getLevel) + .orElseGet(this::getDefaultLevel); } public DateFormat getDateTimeFormat() { - try { - return new SimpleDateFormat(environment.getStringProperty(SYSTEM_PREFIX + "dateTimeFormat", DEFAULT_DATE_TIME_FORMAT)); - } catch (final IllegalArgumentException e) { - return new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT); - } + return propertyResolver.getString(LoggingSystemProperties.SIMPLE_DATE_TIME_FORMAT) + .map(format -> { + try { + return new SimpleDateFormat(format); + } catch (final IllegalArgumentException ignored) { + return null; + } + }) + .orElseGet(() -> new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT)); } public String getLogFileName() { - return environment.getStringProperty(SYSTEM_PREFIX + "logFile", "system.err"); + return propertyResolver.getString(LoggingSystemProperties.SIMPLE_LOG_FILE).orElse("system.err"); } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java index 6e72aa9fabc..ee8189f8aa6 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.spi.ExtendedLogger; import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.spi.LoggerRegistry; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.spi.LoggingSystem; /** * A simple {@link LoggerContext} implementation. @@ -42,9 +42,6 @@ public class SimpleLoggerContext implements LoggerContext { /** The default format to use when formatting dates */ protected static final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz"; - /** All system properties used by SimpleLog start with this */ - protected static final String SYSTEM_PREFIX = "org.apache.logging.log4j.simplelog."; - private final SimpleLoggerConfiguration configuration; private final PrintStream stream; @@ -55,7 +52,7 @@ public class SimpleLoggerContext implements LoggerContext { * Constructs a new initialized instance. */ public SimpleLoggerContext() { - this(new SimpleLoggerConfiguration(PropertiesUtil.getProperties("simplelog"))); + this(new SimpleLoggerConfiguration(LoggingSystem.getPropertyResolver())); } public SimpleLoggerContext(final SimpleLoggerConfiguration configuration) { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java index 3760897b76c..a5477c8cc35 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java @@ -110,7 +110,7 @@ public AbstractLogger() { * @param name the logger name */ public AbstractLogger(final String name) { - this(name, LoggingSystem.getMessageFactory()); + this(name, null); } /** @@ -120,9 +120,21 @@ public AbstractLogger(final String name) { * @param messageFactory the message factory, if null then use the default message factory. */ public AbstractLogger(final String name, final MessageFactory messageFactory) { + this(name, messageFactory, null); + } + + /** + * Creates a new named logger with a particular {@link MessageFactory} and {@link FlowMessageFactory}. + * + * @param name the logger name + * @param messageFactory the message factory to use or null to use the default message factory + * @param flowMessageFactory the flow message factory to use or null to use the default flow message factory + * @since 3.0.0 + */ + public AbstractLogger(final String name, final MessageFactory messageFactory, final FlowMessageFactory flowMessageFactory) { this.name = name; this.messageFactory = messageFactory == null ? LoggingSystem.getMessageFactory() : messageFactory; - this.flowMessageFactory = LoggingSystem.getFlowMessageFactory(); + this.flowMessageFactory = flowMessageFactory == null ? LoggingSystem.getFlowMessageFactory() : flowMessageFactory; this.logBuilder = new LocalLogBuilder(this); } @@ -1975,7 +1987,7 @@ public void printf(final Level level, final String format, final Object... param } } - @PerformanceSensitive + @PerformanceSensitive("MaxInlineSize") // NOTE: This is a hot method. Current implementation compiles to 30 bytes of byte code. // This is within the 35 byte MaxInlineSize threshold. Modify with care! private void logMessageSafely(final String fqcn, final Level level, final Marker marker, final Message msg, @@ -1988,7 +2000,7 @@ private void logMessageSafely(final String fqcn, final Level level, final Marker } } - @PerformanceSensitive + @PerformanceSensitive("MaxInlineSize") // NOTE: This is a hot method. Current implementation compiles to 33 bytes of byte code. // This is within the 35 byte MaxInlineSize threshold. Modify with care! private void logMessageTrackRecursion(final String fqcn, @@ -2034,7 +2046,7 @@ public static int getRecursionDepth() { return getRecursionDepthHolder()[0]; } - @PerformanceSensitive + @PerformanceSensitive("MaxInlineSize") // NOTE: This is a hot method. Current implementation compiles to 27 bytes of byte code. // This is within the 35 byte MaxInlineSize threshold. Modify with care! private void tryLogMessage(final String fqcn, @@ -2051,7 +2063,7 @@ private void tryLogMessage(final String fqcn, } } - @PerformanceSensitive + @PerformanceSensitive("MaxInlineSize") // NOTE: This is a hot method. Current implementation compiles to 15 bytes of byte code. // This is within the 35 byte MaxInlineSize threshold. Modify with care! private StackTraceElement getLocation(final String fqcn) { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ClassFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ClassFactory.java new file mode 100644 index 00000000000..267406c030e --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ClassFactory.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.spi; + +import java.util.Optional; + +import org.apache.logging.log4j.util.LowLevelLogUtil; + +/** + * Indirect form of a {@link ClassLoader} that may be used for loading extensions or plugins. + * + * @since 3.0.0 + */ +@FunctionalInterface +public interface ClassFactory { + + /** + * Loads the given class using its binary name. + * + * @see ClassLoader#loadClass(String) + */ + Class loadClass(final String name) throws ClassNotFoundException; + + /** + * Attempts to load the given class by binary name as an expected subclass of the provided superclass. + * + * @param name binary name of the class to try to load + * @param superclass expected superclass of the loaded class + * @param the expected supertype of the loaded class + * @return the loaded class if successful or an empty optional otherwise + */ + default Optional> tryGetClass(final String name, final Class superclass) { + try { + final Class clazz = loadClass(name); + return Optional.of(clazz.asSubclass(superclass)); + } catch (final ClassNotFoundException | LinkageError | ClassCastException e) { + LowLevelLogUtil.logException("Cannot find class " + name + " with superclass " + superclass.getName(), e); + return Optional.empty(); + } + } + + /** + * Loads the given class by binary name as an expected subclass of the provided superclass. + * + * @param name binary name of the class to try to load + * @param superclass expected superclass of the loaded class + * @param the expected supertype of the loaded class + * @return the loaded class + * @throws ClassNotFoundException if the class could not be found with the expected superclass + */ + default Class getClass(final String name, final Class superclass) throws ClassNotFoundException { + return tryGetClass(name, superclass).orElseThrow(() -> + new ClassNotFoundException("Cannot find class " + name + " with superclass " + superclass.getName())); + } + + /** + * Checks if a class with the given binary name can be found. + * + * @param name binary name of the class to check for existence + * @return true if a class with the given binary name could be loaded + */ + default boolean isClassAvailable(final String name) { + try { + return loadClass(name) != null; + } catch (final ClassNotFoundException | LinkageError ignored) { + return false; + } + } + +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java index 7650c79b580..96f075b7140 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java @@ -21,7 +21,6 @@ import java.util.Map; import java.util.Objects; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; @@ -51,8 +50,9 @@ class CopyOnWriteSortedArrayThreadContextMap implements ReadOnlyThreadContextMap public CopyOnWriteSortedArrayThreadContextMap() { this( - PropertiesUtil.getProperties().getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE), - PropertiesUtil.getProperties().getIntegerProperty(THREAD_CONTEXT_INITIAL_CAPACITY, THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY) + LoggingSystem.getPropertyResolver().getBoolean(THREAD_CONTEXT_MAP_INHERITABLE), + LoggingSystem.getPropertyResolver().getInt(THREAD_CONTEXT_INITIAL_CAPACITY) + .orElse(THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY) ); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultClassFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultClassFactory.java new file mode 100644 index 00000000000..3c773db0100 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultClassFactory.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.spi; + +import java.util.Optional; + +import org.apache.logging.log4j.util.LoaderUtil; +import org.apache.logging.log4j.util.LowLevelLogUtil; + +/** + * Default strategy for locating and loading classes by name. This attempts to load a class using multiple available + * ClassLoaders depending on the runtime environment. + * + * @see LoaderUtil#getClassLoaders() + */ +public class DefaultClassFactory implements ClassFactory { + @Override + public Class loadClass(final String name) throws ClassNotFoundException { + ClassNotFoundException exception = null; + for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) { + try { + return classLoader.loadClass(name); + } catch (final ClassNotFoundException e) { + if (exception == null) { + exception = e; + } else { + exception.addSuppressed(e); + } + } + } + throw exception != null ? exception : new ClassNotFoundException(name); + } + + @Override + public Optional> tryGetClass(final String name, final Class superclass) { + for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) { + final Class clazz; + try { + clazz = classLoader.loadClass(name); + return Optional.of(clazz.asSubclass(superclass)); + } catch (final ClassNotFoundException | LinkageError | ClassCastException ignored) { + } + } + LowLevelLogUtil.log("Unable to get class " + name + " with superclass " + superclass.getName()); + return Optional.empty(); + } + + @Override + public boolean isClassAvailable(final String name) { + for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) { + try { + if (classLoader.loadClass(name) != null) { + return true; + } + } catch (final ClassNotFoundException | LinkageError ignored) { + } + } + return false; + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultInstanceFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultInstanceFactory.java new file mode 100644 index 00000000000..9b52802811c --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultInstanceFactory.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.spi; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Optional; + +import org.apache.logging.log4j.util.InternalException; +import org.apache.logging.log4j.util.LowLevelLogUtil; + +/** + * Default strategy for creating instances of classes. This wraps security-sensitive reflection lookups using + * {@link AccessController} when a {@link SecurityManager} is enabled. + */ +public class DefaultInstanceFactory implements InstanceFactory { + @Override + public T getInstance(final Class type) { + try { + final Constructor constructor = getConstructor(type); + return constructor.newInstance(); + } catch (final NoSuchMethodException | InstantiationException | LinkageError | IllegalAccessException e) { + throw new InternalException(e); + } catch (final InvocationTargetException e) { + throw new InternalException(e.getCause()); + } + } + + private static Constructor getConstructor(final Class type) throws NoSuchMethodException, IllegalAccessException { + if (System.getSecurityManager() == null) { + return doGetConstructor(type); + } + final PrivilegedExceptionAction> action = () -> doGetConstructor(type); + try { + return AccessController.doPrivileged(action); + } catch (final PrivilegedActionException e) { + final Throwable cause = e.getCause(); + if (cause instanceof NoSuchMethodException) { + throw (NoSuchMethodException) cause; + } + if (cause instanceof IllegalAccessException) { + throw (IllegalAccessException) cause; + } + throw new InternalException(cause); + } + } + + private static Constructor doGetConstructor(final Class type) throws NoSuchMethodException, IllegalAccessException { + try { + return type.getConstructor(); + } catch (final NoSuchMethodException ignored) { + final Constructor constructor = type.getDeclaredConstructor(); + if (!(constructor.canAccess(null) || constructor.trySetAccessible())) { + throw new IllegalAccessException("Cannot access " + constructor); + } + return constructor; + } + } + + @Override + public Optional tryGetInstance(final Class type) { + try { + Constructor constructor = getConstructor(type); + return Optional.of(constructor.newInstance()); + } catch (final NoSuchMethodException e) { + LowLevelLogUtil.logException("Unable to find a default constructor for " + type, e); + return Optional.empty(); + } catch (final IllegalAccessException | SecurityException | InternalException e) { + LowLevelLogUtil.logException("Unable to access constructor for " + type, e); + return Optional.empty(); + } catch (final InvocationTargetException e) { + LowLevelLogUtil.logException("Exception thrown by constructor for " + type, e.getCause()); + } catch (final InstantiationException | LinkageError e) { + LowLevelLogUtil.logException("Unable to create instance of " + type, e); + } + return Optional.empty(); + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java index f369803c63d..e704ff47265 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java @@ -23,7 +23,6 @@ import org.apache.logging.log4j.util.BiConsumer; import org.apache.logging.log4j.util.Cast; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.TriConsumer; @@ -65,7 +64,7 @@ public DefaultThreadContextMap() { } public DefaultThreadContextMap(final boolean useMap) { - this(useMap, PropertiesUtil.getProperties().getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE)); + this(useMap, LoggingSystem.getPropertyResolver().getBoolean(THREAD_CONTEXT_MAP_INHERITABLE)); } DefaultThreadContextMap(final boolean useMap, final boolean inheritableMap) { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ExtendedLoggerWrapper.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ExtendedLoggerWrapper.java index 6c9c6c9a8c9..8001c568f24 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ExtendedLoggerWrapper.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ExtendedLoggerWrapper.java @@ -18,6 +18,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.message.FlowMessageFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.util.StackLocatorUtil; @@ -35,17 +36,32 @@ public class ExtendedLoggerWrapper extends AbstractLogger { protected final ExtendedLogger logger; /** - * Constructor that wraps and existing Logger. + * Constructor that wraps an existing Logger. * * @param logger The Logger to wrap. * @param name The name of the Logger. - * @param messageFactory TODO + * @param messageFactory the MessageFactory to use */ public ExtendedLoggerWrapper(final ExtendedLogger logger, final String name, final MessageFactory messageFactory) { super(name, messageFactory); this.logger = logger; } + /** + * Constructor that wraps an existing Logger. + * + * @param logger the Logger to wrap + * @param name the name of the Logger + * @param messageFactory the MessageFactory to use + * @param flowMessageFactory the FlowMessageFactory to use + * @since 3.0.0 + */ + public ExtendedLoggerWrapper(final ExtendedLogger logger, final String name, final MessageFactory messageFactory, + final FlowMessageFactory flowMessageFactory) { + super(name, messageFactory, flowMessageFactory); + this.logger = logger; + } + @Override public Level getLevel() { return logger.getLevel(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java index 2a258c441cc..4f580650108 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java @@ -21,13 +21,13 @@ import java.util.Map; import java.util.Objects; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import static org.apache.logging.log4j.spi.LoggingSystem.THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY; -import static org.apache.logging.log4j.spi.LoggingSystemProperties.*; +import static org.apache.logging.log4j.spi.LoggingSystemProperties.THREAD_CONTEXT_INITIAL_CAPACITY; +import static org.apache.logging.log4j.spi.LoggingSystemProperties.THREAD_CONTEXT_MAP_INHERITABLE; /** * {@code SortedArrayStringMap}-based implementation of the {@code ThreadContextMap} interface that attempts not to @@ -45,8 +45,9 @@ class GarbageFreeSortedArrayThreadContextMap implements ReadOnlyThreadContextMap public GarbageFreeSortedArrayThreadContextMap() { this( - PropertiesUtil.getProperties().getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE), - PropertiesUtil.getProperties().getIntegerProperty(THREAD_CONTEXT_INITIAL_CAPACITY, THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY) + LoggingSystem.getPropertyResolver().getBoolean(THREAD_CONTEXT_MAP_INHERITABLE), + LoggingSystem.getPropertyResolver().getInt(THREAD_CONTEXT_INITIAL_CAPACITY) + .orElse(THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY) ); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/InstanceFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/InstanceFactory.java new file mode 100644 index 00000000000..6ef12f29b73 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/InstanceFactory.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.spi; + +import java.util.Optional; + +/** + * Strategy for managing instances of classes created dynamically rather than statically. + */ +public interface InstanceFactory { + /** + * Gets or creates an instance of the given class. At minimum, this should support instantiating classes with a + * public no-argument constructor, though more sophisticated implementations may support additional dependency + * injection. The instance returned is not guaranteed to be a fresh instance. + * + * @param type the class to look up an instance for + * @param the type of the instance + * @return an instance of the requested class + * @throws org.apache.logging.log4j.util.InternalException if there was a problem creating the instance + */ + T getInstance(final Class type); + + /** + * Attempts to get or create an instance of the given class. + * + * @param type the class to look up an instance for + * @param the type of the instance + * @return an instance of the request class or an empty optional + * @see #getInstance(Class) + */ + Optional tryGetInstance(final Class type); +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java index c4ce580266f..b33a14ebf3e 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java @@ -16,13 +16,15 @@ */ package org.apache.logging.log4j.spi; +import java.util.Optional; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.MessageFactory; /** * Anchor point for logging implementations. */ -public interface LoggerContext { +public interface LoggerContext extends InstanceFactory { /** * Empty array. @@ -163,4 +165,14 @@ default Object removeObject(final String key) { default boolean removeObject(final String key, final Object value) { return false; } + + @Override + default T getInstance(final Class type) { + return LoggingSystem.getInstance().getInstanceFactory().getInstance(type); + } + + @Override + default Optional tryGetInstance(final Class type) { + return LoggingSystem.getInstance().getInstanceFactory().tryGetInstance(type); + } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java index 3f7981fc629..9c31faa86d8 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java @@ -19,17 +19,15 @@ import java.io.IOException; import java.io.InputStream; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Properties; import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; @@ -41,12 +39,15 @@ import org.apache.logging.log4j.message.ReusableMessageFactory; import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.util.DefaultPropertyResolver; import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.JsonResourcePropertySource; import org.apache.logging.log4j.util.Lazy; import org.apache.logging.log4j.util.LoaderUtil; import org.apache.logging.log4j.util.LowLevelLogUtil; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertiesPropertySource; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.PropertySource; import org.apache.logging.log4j.util.ServiceRegistry; import static org.apache.logging.log4j.spi.LoggingSystemProperties.*; @@ -65,6 +66,10 @@ public class LoggingSystem { private static final String PROVIDER_RESOURCE = "META-INF/log4j-provider.properties"; private static final String API_VERSION = "Log4jAPIVersion"; private static final String[] COMPATIBLE_API_VERSIONS = {"3.0.0"}; + private static final String JSON_FILE_NAME = "log4j2.component.json"; + private static final String PROPERTIES_FILE_NAME = "log4j2.component.properties"; + private static final String DEFAULT_JSON_FILE_NAME = "META-INF/log4j2.default.component.json"; + private static final String DEFAULT_PROPERTIES_FILE_NAME = "META-INF/log4j2.default.component.properties"; public static final int THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY = 16; @@ -72,33 +77,15 @@ public class LoggingSystem { private final Lock initializationLock = new ReentrantLock(); private volatile SystemProvider provider; - private final Lazy environmentLazy = Lazy.relaxed(PropertiesUtil::getProperties); - private final Lazy loggerContextFactoryLazy = environmentLazy.map(environment -> - getProvider().createLoggerContextFactory(environment)); - private final Lazy messageFactoryLazy = environmentLazy.map(environment -> { - final String className = environment.getStringProperty(LOGGER_MESSAGE_FACTORY_CLASS); - if (className != null) { - final MessageFactory factory = createInstance(className, MessageFactory.class); - if (factory != null) { - return factory; - } - } - return Constants.isThreadLocalsEnabled() ? new ReusableMessageFactory() : new ParameterizedMessageFactory(); - }); - private final Lazy flowMessageFactoryLazy = environmentLazy.map(environment -> { - final String className = environment.getStringProperty(LOGGER_FLOW_MESSAGE_FACTORY_CLASS); - if (className != null) { - final FlowMessageFactory factory = createInstance(className, FlowMessageFactory.class); - if (factory != null) { - return factory; - } - } - return new DefaultFlowMessageFactory(); - }); - private final Lazy> threadContextMapFactoryLazy = environmentLazy.map(environment -> - () -> getProvider().createContextMap(environment)); - private final Lazy> threadContextStackFactoryLazy = environmentLazy.map(environment -> - () -> getProvider().createContextStack(environment)); + private final PropertyResolver propertyResolver = new DefaultPropertyResolver(); + private final Lazy classFactoryLazy = Lazy.relaxed(DefaultClassFactory::new); + private final Lazy instanceFactoryLazy = Lazy.relaxed(DefaultInstanceFactory::new); + private final Lazy loggerContextFactoryLazy = Lazy.lazy(() -> + getProvider().createLoggerContextFactory()); + + private LoggingSystem() { + loadPropertySources(propertyResolver); + } /** * Acquires a lock on the initialization of locating a logging system provider. This lock should be @@ -121,6 +108,34 @@ public void releaseInitializationLock() { initializationLock.unlock(); } + public PropertyResolver propertyResolver() { + return propertyResolver; + } + + public void setLoggerContextFactory(final LoggerContextFactory loggerContextFactory) { + loggerContextFactoryLazy.set(loggerContextFactory); + } + + public LoggerContextFactory getLoggerContextFactory() { + return loggerContextFactoryLazy.value(); + } + + public void setClassFactory(final ClassFactory classFactory) { + classFactoryLazy.set(classFactory); + } + + public ClassFactory getClassFactory() { + return classFactoryLazy.value(); + } + + public void setInstanceFactory(final InstanceFactory instanceFactory) { + instanceFactoryLazy.set(instanceFactory); + } + + public InstanceFactory getInstanceFactory() { + return instanceFactoryLazy.value(); + } + private SystemProvider getProvider() { var provider = this.provider; if (provider == null) { @@ -158,24 +173,38 @@ private SystemProvider findProvider() { return new SystemProvider(provider); } - public void setLoggerContextFactory(final LoggerContextFactory loggerContextFactory) { - loggerContextFactoryLazy.set(loggerContextFactory); + private Optional tryGetInstance(final String className, final Class type) { + return getClassFactory() + .tryGetClass(className, type) + .flatMap(getInstanceFactory()::tryGetInstance); } - public void setMessageFactory(final MessageFactory messageFactory) { - messageFactoryLazy.set(messageFactory); + private boolean isThreadLocalsEnabled() { + final String value = propertyResolver.getString(SYSTEM_THREAD_LOCALS_ENABLED).orElse("true"); + return "calculate".equalsIgnoreCase(value) ? !isWebAppEnabled() : "true".equalsIgnoreCase(value); } - public void setFlowMessageFactory(final FlowMessageFactory flowMessageFactory) { - flowMessageFactoryLazy.set(flowMessageFactory); + private boolean isWebAppEnabled() { + return propertyResolver.getString(SYSTEM_ENABLE_WEBAPP) + .filter(value -> "calculate".equalsIgnoreCase(value) ? isServletClassAvailable() : "true".equalsIgnoreCase(value)) + .isPresent(); } - public void setThreadContextMapFactory(final Supplier threadContextMapFactory) { - threadContextMapFactoryLazy.set(threadContextMapFactory); + private boolean isServletClassAvailable() { + return getClassFactory().isClassAvailable("javax.servlet.Servlet") || + getClassFactory().isClassAvailable("jakarta.servlet.Servlet"); } - public void setThreadContextStackFactory(final Supplier threadContextStackFactory) { - threadContextStackFactoryLazy.set(threadContextStackFactory); + private MessageFactory newMessageFactory(final String context) { + return propertyResolver.getString(context, LOGGER_MESSAGE_FACTORY_CLASS) + .flatMap(className -> tryGetInstance(className, MessageFactory.class)) + .orElseGet(() -> isThreadLocalsEnabled() ? ReusableMessageFactory.INSTANCE : ParameterizedMessageFactory.INSTANCE); + } + + private FlowMessageFactory newFlowMessageFactory(final String context) { + return propertyResolver.getString(context, LOGGER_FLOW_MESSAGE_FACTORY_CLASS) + .flatMap(className -> tryGetInstance(className, FlowMessageFactory.class)) + .orElseGet(DefaultFlowMessageFactory::new); } /** @@ -185,34 +214,96 @@ public static LoggingSystem getInstance() { return SYSTEM.value(); } + public static PropertyResolver getPropertyResolver() { + return getInstance().propertyResolver; + } + /** * Gets the current LoggerContextFactory. This may initialize the instance if this is the first time it was * requested. */ - public static LoggerContextFactory getLoggerContextFactory() { - return getInstance().loggerContextFactoryLazy.value(); + public static LoggerContextFactory loggerContextFactory() { + return getInstance().getLoggerContextFactory(); + } + + public static MessageFactory createMessageFactory(final String context) { + return getInstance().newMessageFactory(context); + } + + public static FlowMessageFactory createFlowMessageFactory(final String context) { + return getInstance().newFlowMessageFactory(context); } public static MessageFactory getMessageFactory() { - return getInstance().messageFactoryLazy.value(); + return createMessageFactory(PropertyResolver.DEFAULT_CONTEXT); } public static FlowMessageFactory getFlowMessageFactory() { - return getInstance().flowMessageFactoryLazy.value(); + return createFlowMessageFactory(PropertyResolver.DEFAULT_CONTEXT); } /** * Creates a new ThreadContextMap. */ public static ThreadContextMap createContextMap() { - return getInstance().threadContextMapFactoryLazy.value().get(); + return getInstance().getProvider().createContextMap(); } /** * Creates a new ThreadContextStack. */ public static ThreadContextStack createContextStack() { - return getInstance().threadContextStackFactoryLazy.value().get(); + return getInstance().getProvider().createContextStack(); + } + + private static void loadPropertySources(final PropertyResolver resolver) { + loadPropertySourceServices(resolver); + loadJsonSources(resolver, DEFAULT_JSON_FILE_NAME, 1000); + loadPropertiesSources(resolver, DEFAULT_PROPERTIES_FILE_NAME, 1000); + loadJsonSources(resolver, JSON_FILE_NAME, 50); + loadPropertiesSources(resolver, PROPERTIES_FILE_NAME, 50); + } + + private static void loadPropertySourceServices(final PropertyResolver resolver) { + ServiceRegistry.getInstance() + .getServices(PropertySource.class, MethodHandles.lookup(), null) + .forEach(resolver::addSource); + } + + private static void loadJsonSources(final PropertyResolver resolver, final String name, final int priority) { + LoaderUtil.findResources(name, false) + .stream() + .map(url -> loadJsonSource(url, priority)) + .filter(Objects::nonNull) + .forEach(resolver::addSource); + } + + private static PropertySource loadJsonSource(final URL url, final int priority) { + try { + return JsonResourcePropertySource.fromUrl(url, priority); + } catch (final RuntimeException e) { + LowLevelLogUtil.logException("Unable to read " + url, e); + return null; + } + } + + private static void loadPropertiesSources(final PropertyResolver resolver, final String name, final int priority) { + LoaderUtil.findResources(name, false) + .stream() + .map(url -> loadPropertiesSource(url, priority)) + .filter(Objects::nonNull) + .forEach(resolver::addSource); + } + + private static PropertySource loadPropertiesSource(final URL url, final int priority) { + final Properties properties = new Properties(); + try (final InputStream in = url.openStream()) { + properties.load(in); + return new PropertiesPropertySource(properties, priority); + } catch (final IOException e) { + LowLevelLogUtil.logException("Unable to read " + url, e); + return null; + } } private static List loadDefaultProviders() { @@ -251,46 +342,7 @@ private static boolean validVersion(final String version) { return false; } - private static T tryInstantiate(final Class clazz) { - Constructor constructor; - try { - constructor = clazz.getConstructor(); - } catch (final NoSuchMethodException ignored) { - try { - constructor = clazz.getDeclaredConstructor(); - if (!(constructor.canAccess(null) || constructor.trySetAccessible())) { - LowLevelLogUtil.log("Unable to access constructor for " + clazz); - return null; - } - } catch (final NoSuchMethodException e) { - LowLevelLogUtil.logException("Unable to find a default constructor for " + clazz, e); - return null; - } - } - try { - return constructor.newInstance(); - } catch (final InvocationTargetException e) { - LowLevelLogUtil.logException("Exception thrown by constructor for " + clazz, e.getCause()); - } catch (final InstantiationException | LinkageError e) { - LowLevelLogUtil.logException("Unable to create instance of " + clazz, e); - } catch (final IllegalAccessException e) { - LowLevelLogUtil.logException("Unable to access constructor for " + clazz, e); - } - return null; - } - - private static T createInstance(final String className, final Class type) { - try { - final Class loadedClass = LoaderUtil.loadClass(className); - final Class typedClass = loadedClass.asSubclass(type); - return tryInstantiate(typedClass); - } catch (final ClassNotFoundException | ClassCastException e) { - LowLevelLogUtil.logException(String.format("Unable to load %s class '%s'", type.getSimpleName(), className), e); - return null; - } - } - - private static class SystemProvider { + private class SystemProvider { private final Provider provider; private SystemProvider() { @@ -301,27 +353,18 @@ private SystemProvider(final Provider provider) { this.provider = provider; } - public LoggerContextFactory createLoggerContextFactory(final PropertyEnvironment environment) { - final String customFactoryClass = environment.getStringProperty(LogManager.FACTORY_PROPERTY_NAME); - if (customFactoryClass != null) { - final LoggerContextFactory customFactory = createInstance(customFactoryClass, LoggerContextFactory.class); - if (customFactory != null) { - return customFactory; - } - } - if (provider != null) { - final Class factoryClass = provider.loadLoggerContextFactory(); - if (factoryClass != null) { - final LoggerContextFactory factory = tryInstantiate(factoryClass); - if (factory != null) { - return factory; - } - } - } - LowLevelLogUtil.log("Log4j could not find a logging implementation. " + - "Please add log4j-core dependencies to classpath or module path. " + - "Using SimpleLogger to log to the console."); - return SimpleLoggerContextFactory.INSTANCE; + public LoggerContextFactory createLoggerContextFactory() { + return propertyResolver.getString(LogManager.FACTORY_PROPERTY_NAME) + .flatMap(className -> tryGetInstance(className, LoggerContextFactory.class)) + .or(() -> Optional.ofNullable(provider) + .map(Provider::loadLoggerContextFactory) + .flatMap(getInstanceFactory()::tryGetInstance)) + .orElseGet(() -> { + LowLevelLogUtil.log("Log4j could not find a logging implementation. " + + "Please add log4j-core dependencies to classpath or module path. " + + "Using SimpleLogger to log to the console."); + return SimpleLoggerContextFactory.INSTANCE; + }); } /** @@ -344,44 +387,37 @@ public LoggerContextFactory createLoggerContextFactory(final PropertyEnvironment * @see ReadOnlyThreadContextMap * @see org.apache.logging.log4j.ThreadContext */ - public ThreadContextMap createContextMap(final PropertyEnvironment environment) { - final String customThreadContextMap = environment.getStringProperty(THREAD_CONTEXT_MAP_CLASS); - if (customThreadContextMap != null) { - final ThreadContextMap customContextMap = createInstance(customThreadContextMap, ThreadContextMap.class); - if (customContextMap != null) { - return customContextMap; - } - } - final boolean disableMap = environment.getBooleanProperty(THREAD_CONTEXT_MAP_DISABLED, - environment.getBooleanProperty(THREAD_CONTEXT_DISABLED)); - if (disableMap) { - return new NoOpThreadContextMap(); - } - final Class mapClass = provider.loadThreadContextMap(); - if (mapClass != null) { - final ThreadContextMap map = tryInstantiate(mapClass); - if (map != null) { - return map; - } - } - final boolean threadLocalsEnabled = Constants.isThreadLocalsEnabled(); - final boolean garbageFreeEnabled = environment.getBooleanProperty(THREAD_CONTEXT_GARBAGE_FREE_ENABLED); - final boolean inheritableMap = environment.getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE); - final int initialCapacity = environment.getIntegerProperty(THREAD_CONTEXT_INITIAL_CAPACITY, - THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY); - if (threadLocalsEnabled) { - if (garbageFreeEnabled) { - return new GarbageFreeSortedArrayThreadContextMap(inheritableMap, initialCapacity); - } - return new CopyOnWriteSortedArrayThreadContextMap(inheritableMap, initialCapacity); - } - return new DefaultThreadContextMap(true, inheritableMap); + public ThreadContextMap createContextMap() { + return propertyResolver.getString(THREAD_CONTEXT_MAP_CLASS) + .flatMap(className -> tryGetInstance(className, ThreadContextMap.class)) + .orElseGet(() -> { + final boolean enabled = propertyResolver.getBoolean(THREAD_CONTEXT_MAP_ENABLED, true) && + propertyResolver.getBoolean(THREAD_CONTEXT_ENABLED, true); + if (!enabled) { + return new NoOpThreadContextMap(); + } + return Optional.ofNullable(provider.loadThreadContextMap()) + .flatMap(getInstanceFactory()::tryGetInstance) + .orElseGet(() -> { + final boolean garbageFreeEnabled = propertyResolver.getBoolean(THREAD_CONTEXT_GARBAGE_FREE_ENABLED); + final boolean inheritableMap = propertyResolver.getBoolean(THREAD_CONTEXT_MAP_INHERITABLE); + final int initialCapacity = propertyResolver.getInt(THREAD_CONTEXT_INITIAL_CAPACITY) + .orElse(THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY); + if (isThreadLocalsEnabled()) { + if (garbageFreeEnabled) { + return new GarbageFreeSortedArrayThreadContextMap(inheritableMap, initialCapacity); + } + return new CopyOnWriteSortedArrayThreadContextMap(inheritableMap, initialCapacity); + } + return new DefaultThreadContextMap(true, inheritableMap); + }); + }); } - public ThreadContextStack createContextStack(final PropertyEnvironment environment) { - final boolean disableStack = environment.getBooleanProperty(THREAD_CONTEXT_STACK_DISABLED, - environment.getBooleanProperty(THREAD_CONTEXT_DISABLED)); - return new DefaultThreadContextStack(!disableStack); + public ThreadContextStack createContextStack() { + final boolean enabled = propertyResolver.getBoolean(THREAD_CONTEXT_STACK_ENABLED, true) && + propertyResolver.getBoolean(THREAD_CONTEXT_ENABLED, true); + return new DefaultThreadContextStack(enabled); } } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystemProperties.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystemProperties.java index 47fdd20741c..c3b66b8bfcb 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystemProperties.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystemProperties.java @@ -23,20 +23,19 @@ import org.apache.logging.log4j.status.StatusListener; import org.apache.logging.log4j.util.EnvironmentPropertySource; import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Unbox; /** * Centralized list of property name constants that can be configured in the Log4j API. These properties may be * specified as system properties, environment variables (see {@link EnvironmentPropertySource}), or in a classpath - * resource file named {@code log4j2.component.properties}. + * resource file named {@code log4j2.component.properties} or {@code log4j2.component.json}. Properties are all + * prefixed with {@code log4j2.*.} for default values or {@code log4j2.ContextName.} for named context values. * * @since 3.0.0 - * @see PropertiesUtil + * @see org.apache.logging.log4j.util.PropertyResolver + * @see Properties Enhancement Proposal */ public final class LoggingSystemProperties { - // TODO: rename properties according to established theme in - // https://cwiki.apache.org/confluence/display/LOGGING/Properties+Enhancement /** * Property to enable TRACE-level debug logging in the Log4j system itself. @@ -49,66 +48,61 @@ public final class LoggingSystemProperties { public static final String SYSTEM_DEBUG = "log4j2.*.System.debug"; /** - * Property to override webapp detection. Without this property, the presence of the {@code Servlet} interface + * Property to override webapp detection. When set to {@code calculate}, the presence of the {@code Servlet} interface * (from either {@code javax} or {@code jakarta}) is checked to see if this is a webapp. */ - // Web.enableWebApp : calculate | true | false - public static final String SYSTEM_IS_WEBAPP = "log4j2.isWebapp"; + public static final String SYSTEM_ENABLE_WEBAPP = "log4j2.*.Web.enableWebApp"; /** - * Property to override the use of thread-local values for garbage-free logging. + * Property to override the use of thread-local values for garbage-free logging. When set to {@code calculate}, + * the result depends on whether web app mode is enabled. * * @see LOG4J2-1270 + * @see #SYSTEM_ENABLE_WEBAPP */ - // GC.enableThreadLocals : calculate | true | false - public static final String SYSTEM_THREAD_LOCALS_ENABLED = "log4j2.enableThreadlocals"; + public static final String SYSTEM_THREAD_LOCALS_ENABLED = "log4j2.*.GC.enableThreadLocals"; /** - * Property to ignore the thread context ClassLoader when set to {@code true}. + * Property to set to either an empty string or {@code true} to ignore the thread context class loader when + * scanning for class loaders. * * @see LoaderUtil */ - // TODO: see if this can be removed - public static final String LOADER_IGNORE_THREAD_CONTEXT_LOADER = "log4j2.ignoreTCL"; + public static final String LOADER_IGNORE_THREAD_CONTEXT_LOADER = "log4j2.*.System.ignoreTCL"; /** - * Property to force use of the thread context ClassLoader. + * Property to force use of the thread context ClassLoader when set to an empty string or {@code true} to force + * usage of only the thread context class loader. * * @see LoaderUtil */ - // TODO: see if this can be removed - public static final String LOADER_FORCE_THREAD_CONTEXT_LOADER = "log4j2.forceTCLOnly"; + public static final String LOADER_FORCE_THREAD_CONTEXT_LOADER = "log4j2.*.System.forceTCL"; /** * Property to override the default ringbuffer size used in {@link Unbox}. The default value is 32. */ - // GC.unboxRingBufferSize - public static final String UNBOX_RING_BUFFER_SIZE = "log4j2.unboxRingbufferSize"; + public static final String UNBOX_RING_BUFFER_SIZE = "log4j2.*.GC.unboxRingBufferSize"; /** * Property to set to the fully qualified class name of a custom implementation of {@link LoggerContextFactory}. */ - // LoggerContext.factory - public static final String LOGGER_CONTEXT_FACTORY_CLASS = "log4j2.loggerContextFactory"; + public static final String LOGGER_CONTEXT_FACTORY_CLASS = "log4j2.*.LoggerContext.factory"; /** * Property to override the default {@link MessageFactory} class. */ - // Message.messageFactory - public static final String LOGGER_MESSAGE_FACTORY_CLASS = "log4j2.messageFactory"; + public static final String LOGGER_MESSAGE_FACTORY_CLASS = "log4j2.*.Message.messageFactory"; /** * Property to override the default {@link FlowMessageFactory} class. */ - // Message.flowMessageFactory - public static final String LOGGER_FLOW_MESSAGE_FACTORY_CLASS = "log4j2.flowMessageFactory"; + public static final String LOGGER_FLOW_MESSAGE_FACTORY_CLASS = "log4j2.*.Message.flowMessageFactory"; /** * Property to override the default maximum nesting depth of map messages to format in JSON output. The * default value is 8. */ - // Message.jsonFormatterMaxDepth - public static final String LOGGER_MAP_MESSAGE_JSON_FORMATTER_MAX_DEPTH = "log4j2.mapMessageJsonFormatterMaxDepth"; + public static final String LOGGER_MAP_MESSAGE_JSON_FORMATTER_MAX_DEPTH = "log4j2.*.Message.jsonFormatterMaxDepth"; /** * Property to override the maximum size of the StringBuilder instances used in ringbuffer log events to store @@ -116,86 +110,75 @@ public final class LoggingSystemProperties { * is trimmed to this maximum size. The default value is 518 which allows the StringBuilder to resize three times * from its initial size. */ - // GC.maxReusableMsgSize - public static final String GC_REUSABLE_MESSAGE_MAX_SIZE = "log4j2.maxReusableMsgSize"; + public static final String GC_REUSABLE_MESSAGE_MAX_SIZE = "log4j2.*.GC.maxReusableMsgSize"; - public static final String SIMPLE_SHOW_CONTEXT_MAP = "SimpleLogger.showContextMap"; - public static final String SIMPLE_SHOW_LOG_NAME = "SimpleLogger.showLogName"; - public static final String SIMPLE_SHOW_SHORT_LOG_NAME = "SimpleLogger.showShortLogName"; - public static final String SIMPLE_SHOW_DATE_TIME = "SimpleLogger.showDateTime"; - public static final String SIMPLE_DATE_TIME_FORMAT = "SimpleLogger.dateTimeFormat"; - public static final String SIMPLE_LOG_FILE = "SimpleLogger.logFile"; - public static final String SIMPLE_LOG_LEVEL = "SimpleLogger.logLevel"; - public static final String SIMPLE_LOGGER_LOG_LEVEL = "SimpleLogger.%s.level"; + public static final String SIMPLE_SHOW_CONTEXT_MAP = "log4j2.*.SimpleLogger.showContextMap"; + public static final String SIMPLE_SHOW_LOG_NAME = "log4j2.*.SimpleLogger.showLogName"; + public static final String SIMPLE_SHOW_SHORT_LOG_NAME = "log4j2.*.SimpleLogger.showShortLogName"; + public static final String SIMPLE_SHOW_DATE_TIME = "log4j2.*.SimpleLogger.showDateTime"; + public static final String SIMPLE_DATE_TIME_FORMAT = "log4j2.*.SimpleLogger.dateTimeFormat"; + public static final String SIMPLE_LOG_FILE = "log4j2.*.SimpleLogger.logFile"; + public static final String SIMPLE_LOG_LEVEL = "log4j2.*.SimpleLogger.logLevel"; + public static final String SIMPLE_LOGGER_LOG_LEVEL = "log4j2.*.SimpleLogger.%s.level"; /** * Property that can be configured with the maximum number of status data entries to keep queued. Once the limit is * reached, older entries will be removed as new entries are added. The default value is 200. */ - // StatusLogger.entries - public static final String STATUS_MAX_ENTRIES = "log4j2.statusEntries"; + public static final String STATUS_MAX_ENTRIES = "log4j2.*.StatusLogger.entries"; /** * Property that can be configured with the {@link Level} name to use as the default level for * {@link StatusListener}s. The default value is {@link Level#WARN}. */ - // StatusLogger.statusLoggerLevel - public static final String STATUS_DEFAULT_LISTENER_LEVEL = "log4j2.statusLoggerLevel"; + public static final String STATUS_DEFAULT_LISTENER_LEVEL = "log4j2.*.StatusLogger.statusLoggerLevel"; /** * Property that can be configured with a date-time format string to use as the format for timestamps * in the status logger output. See {@link java.text.SimpleDateFormat} for supported formats. */ - // StatusLogger.dateFormat - public static final String STATUS_DATE_FORMAT = "log4j2.statusLoggerDateFormat"; + public static final String STATUS_DATE_FORMAT = "log4j2.*.StatusLogger.dateFormat"; /** - * Property to control whether {@link ThreadContext} stores map data. If set to {@code true}, then the + * Property to control whether {@link ThreadContext} stores map data. If set to {@code false}, then the * thread context map will be disabled. */ - // ThreadContext.enableMap - public static final String THREAD_CONTEXT_MAP_DISABLED = "log4j2.disableThreadContextMap"; + public static final String THREAD_CONTEXT_MAP_ENABLED = "log4j2.*.ThreadContext.enableMap"; /** - * Property to control whether {@link ThreadContext} stores stack data. If set to {@code true}, then the + * Property to control whether {@link ThreadContext} stores stack data. If set to {@code false}, then the * thread context stack will be disabled. */ - // ThreadContext.enableStack - public static final String THREAD_CONTEXT_STACK_DISABLED = "log4j2.disableThreadContextStack"; + public static final String THREAD_CONTEXT_STACK_ENABLED = "log4j2.*.ThreadContext.enableStack"; /** - * Property to control whether {@link ThreadContext} stores any data. If set to {@code true}, then the + * Property to control whether {@link ThreadContext} stores any data. If set to {@code false}, then the * thread context map and stack will be disabled. */ - // ThreadContext.enabled - public static final String THREAD_CONTEXT_DISABLED = "log4j2.disableThreadContext"; + public static final String THREAD_CONTEXT_ENABLED = "log4j2.*.ThreadContext.enabled"; /** * Property to control whether {@link ThreadContextMap} uses {@link InheritableThreadLocal} when {@code true} or * {@link ThreadLocal} otherwise for holding map data. */ - // ThreadContext.inheritable - public static final String THREAD_CONTEXT_MAP_INHERITABLE = "log4j2.isThreadContextMapInheritable"; + public static final String THREAD_CONTEXT_MAP_INHERITABLE = "log4j2.*.ThreadContext.inheritable"; /** * Property to override the default {@link ThreadContextMap} class. Note that implementation classes should * also implement {@link ReadOnlyThreadContextMap} if they should be accessible to applications via * {@link ThreadContext#getThreadContextMap()}. */ - // TODO: replace with LoggingSystem overrides - public static final String THREAD_CONTEXT_MAP_CLASS = "log4j2.threadContextMap"; + public static final String THREAD_CONTEXT_MAP_CLASS = "log4j2.*.ThreadContext.threadContextMap"; /** * Property to override the initial capacity of the thread context map. The default value is 16. */ - // ThreadContext.initialCapacity - public static final String THREAD_CONTEXT_INITIAL_CAPACITY = "log4j2.threadContextInitialCapacity"; + public static final String THREAD_CONTEXT_INITIAL_CAPACITY = "log4j2.*.ThreadContext.initialCapacity"; /** * Property to override whether to use a garbage-free implementation of {@link ThreadContextMap}. */ - // ThreadContext.garbageFree - public static final String THREAD_CONTEXT_GARBAGE_FREE_ENABLED = "log4j2.garbagefreeThreadContextMap"; + public static final String THREAD_CONTEXT_GARBAGE_FREE_ENABLED = "log4j2.*.ThreadContext.garbageFree"; private LoggingSystemProperties() { throw new UnsupportedOperationException("Utility class"); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java index c458b88a9e3..8f86dc0a733 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java @@ -21,8 +21,8 @@ /** * {@code ThreadContextMap} implementation used when either of system properties - * {@value LoggingSystemProperties#THREAD_CONTEXT_MAP_DISABLED} or - * {@value LoggingSystemProperties#THREAD_CONTEXT_DISABLED} is {@code true}. This implementation does nothing. + * {@value LoggingSystemProperties#THREAD_CONTEXT_MAP_ENABLED} or + * {@value LoggingSystemProperties#THREAD_CONTEXT_ENABLED} is {@code false}. This implementation does nothing. * * @since 2.7 */ diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java index 09828929ddd..197d817da76 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java @@ -259,7 +259,7 @@ public void logMessage(final String fqcn, final Level level, final Marker marker } finally { msgLock.unlock(); } - // LOG4J2-1813 if system property "log4j2.debug" is defined, all status logging is enabled + // LOG4J2-1813 if system property LoggingSystemProperties#SYSTEM_DEBUG is defined, all status logging is enabled if (configuration.isDebugEnabled() || listeners.isEmpty()) { logger.logMessage(fqcn, level, marker, msg, t); } else { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerConfiguration.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerConfiguration.java index 47039d38693..6d3babfc224 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerConfiguration.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerConfiguration.java @@ -20,37 +20,40 @@ import java.text.SimpleDateFormat; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; import static org.apache.logging.log4j.spi.LoggingSystemProperties.*; public class StatusLoggerConfiguration { - private final PropertyEnvironment environment; + private final PropertyResolver resolver; - public StatusLoggerConfiguration(final PropertyEnvironment environment) { - this.environment = environment; + public StatusLoggerConfiguration(final PropertyResolver resolver) { + this.resolver = resolver; } public int getMaxEntries() { - return environment.getIntegerProperty(STATUS_MAX_ENTRIES, 200); + return resolver.getInt(STATUS_MAX_ENTRIES).orElse(200); } public Level getDefaultLevel() { - return Level.toLevel(environment.getStringProperty(STATUS_DEFAULT_LISTENER_LEVEL), Level.WARN); + return resolver.getString(STATUS_DEFAULT_LISTENER_LEVEL) + .map(Level::getLevel) + .orElse(Level.WARN); } public boolean isDebugEnabled() { - return environment.getBooleanProperty(SYSTEM_DEBUG, false, true); + return resolver.getBoolean(SYSTEM_DEBUG, false, true); } public DateFormat getDateTimeFormat() { - final String format = environment.getStringProperty(STATUS_DATE_FORMAT); - if (format != null) { - try { - return new SimpleDateFormat(format); - } catch (final IllegalArgumentException ignored) { - } - } - return null; + return resolver.getString(STATUS_DATE_FORMAT) + .map(format -> { + try { + return new SimpleDateFormat(format); + } catch (final IllegalArgumentException ignored) { + return null; + } + }) + .orElse(null); } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerFactory.java index d7cd8eb0cf1..a638db33917 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerFactory.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLoggerFactory.java @@ -22,7 +22,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.message.ParameterizedNoReferenceMessageFactory; import org.apache.logging.log4j.simple.SimpleLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.spi.LoggingSystem; class StatusLoggerFactory { private static final String STATUS_LOGGER = "StatusLogger"; @@ -45,6 +45,6 @@ StatusLogger createStatusLogger() { } static StatusLoggerFactory getInstance() { - return new StatusLoggerFactory(new StatusLoggerConfiguration(PropertiesUtil.getProperties(STATUS_LOGGER))); + return new StatusLoggerFactory(new StatusLoggerConfiguration(LoggingSystem.getPropertyResolver())); } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/BooleanProperty.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/BooleanProperty.java new file mode 100644 index 00000000000..c6ee703a235 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/BooleanProperty.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +/** + * Describes a property value representing some sort of boolean. Presence or absence of properties can be treated + * as an added dimension to collapse into a boolean value. + * + * @since 3.0.0 + */ +public enum BooleanProperty { + /** Represents the absence of a property value. */ + ABSENT { + @Override + public boolean orElse(final boolean defaultValue) { + return defaultValue; + } + + @Override + public boolean orElse(final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return defaultValueIfAbsent; + } + }, + + /** Represents a non-empty property value that doesn't case-insensitively match the string {@code true}. */ + FALSE { + @Override + public boolean orElse(final boolean defaultValue) { + return false; + } + + @Override + public boolean orElse(final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return false; + } + }, + + /** Represents an empty property value. */ + PRESENT { + @Override + public boolean orElse(final boolean defaultValue) { + return defaultValue; + } + + @Override + public boolean orElse(final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return defaultValueIfPresent; + } + }, + + /** Represents a non-empty property value that case-insensitively matches the string {@code true}. */ + TRUE { + @Override + public boolean orElse(final boolean defaultValue) { + return true; + } + + @Override + public boolean orElse(final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return true; + } + }; + + /** + * Converts this property into a boolean using the given default value when this is {@link #ABSENT} or + * {@link #PRESENT}. + */ + public abstract boolean orElse(final boolean defaultValue); + + /** + * Converts this property into a boolean using the given default value when this is {@link #ABSENT} and a + * given default value when this is {@link #PRESENT}. + */ + public abstract boolean orElse(final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent); + + public static BooleanProperty parse(final String value) { + if (value == null) { + return ABSENT; + } + if (value.isEmpty()) { + return PRESENT; + } + return "true".equalsIgnoreCase(value) ? TRUE : FALSE; + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Constants.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Constants.java index 0044eef6763..dc516c87eb5 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Constants.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Constants.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.util; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; /** @@ -26,9 +30,7 @@ @InternalApi public final class Constants { - private static final LazyBoolean isWebApp = new LazyBoolean(() -> PropertiesUtil.getProperties() - .getBooleanProperty(LoggingSystemProperties.SYSTEM_IS_WEBAPP, - isClassAvailable("javax.servlet.Servlet") || isClassAvailable("jakarta.servlet.Servlet"))); + private static final PrivilegedAction GET_OPERATING_SYSTEM_NAME = () -> System.getProperty("os.name", ""); /** * {@code true} if we think we are running in a web container, based on the boolean value of system property @@ -36,26 +38,20 @@ public final class Constants { * is present in the classpath. */ public static boolean isWebApp() { - return isWebApp.getAsBoolean(); + return isWebApp(LoggingSystem.getPropertyResolver()); } - public static void setWebApp(final boolean webApp) { - isWebApp.setAsBoolean(webApp); + public static boolean isWebApp(final PropertyResolver resolver) { + return resolver + .getString(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP) + .filter(value -> "calculate".equalsIgnoreCase(value) ? isServletClassAvailable() : "true".equalsIgnoreCase(value)) + .isPresent(); } - public static void resetWebApp() { - isWebApp.reset(); + private static boolean isServletClassAvailable() { + return isClassAvailable("javax.servlet.Servlet") || isClassAvailable("jakarta.servlet.Servlet"); } - /** - * @deprecated use {@link #isWebApp()} - */ - @Deprecated(since = "3.0.0", forRemoval = true) - public static final boolean IS_WEB_APP = isWebApp(); - - private static final LazyBoolean threadLocalsEnabled = new LazyBoolean( - () -> !isWebApp() && PropertiesUtil.getProperties().getBooleanProperty(LoggingSystemProperties.SYSTEM_THREAD_LOCALS_ENABLED, true)); - /** * Kill switch for object pooling in ThreadLocals that enables much of the LOG4J2-1270 no-GC behaviour. *

@@ -64,23 +60,16 @@ public static void resetWebApp() { *

*/ public static boolean isThreadLocalsEnabled() { - return threadLocalsEnabled.getAsBoolean(); + return isThreadLocalsEnabled(LoggingSystem.getPropertyResolver()); } - public static void setThreadLocalsEnabled(final boolean enabled) { - threadLocalsEnabled.setAsBoolean(enabled); + public static boolean isThreadLocalsEnabled(final PropertyResolver resolver) { + final String value = resolver + .getString(LoggingSystemProperties.SYSTEM_THREAD_LOCALS_ENABLED) + .orElse("true"); + return "calculate".equalsIgnoreCase(value) ? !isServletClassAvailable() : "true".equalsIgnoreCase(value); } - public static void resetThreadLocalsEnabled() { - threadLocalsEnabled.reset(); - } - - /** - * @deprecated use {@link #isThreadLocalsEnabled()} - */ - @Deprecated(since = "3.0.0", forRemoval = true) - public static final boolean ENABLE_THREADLOCALS = isThreadLocalsEnabled(); - public static final int JAVA_MAJOR_VERSION = getMajorVersion(); /** @@ -92,10 +81,27 @@ public static void resetThreadLocalsEnabled() { *

* @since 2.9 */ - public static final int MAX_REUSABLE_MESSAGE_SIZE = size(LoggingSystemProperties.GC_REUSABLE_MESSAGE_MAX_SIZE, (128 * 2 + 2) * 2 + 2); + public static final int MAX_REUSABLE_MESSAGE_SIZE = LoggingSystem.getPropertyResolver() + .getInt(LoggingSystemProperties.GC_REUSABLE_MESSAGE_MAX_SIZE) + .orElse((128 * 2 + 2) * 2 + 2); + + /** + * Indicates if the current operating system is Windows-based. This may be useful for enabling Windows-specific + * compatibility or dependencies. + * + * @since 3.0.0 + */ + public static boolean isWindows() { + return getOperatingSystemName().startsWith("Windows"); + } - private static int size(final String property, final int defaultValue) { - return PropertiesUtil.getProperties().getIntegerProperty(property, defaultValue); + private static String getOperatingSystemName() { + try { + return System.getSecurityManager() != null ? AccessController.doPrivileged(GET_OPERATING_SYSTEM_NAME) : + GET_OPERATING_SYSTEM_NAME.run(); + } catch (final SecurityException ignored) { + return Strings.EMPTY; + } } /** diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ContextPropertyResolver.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ContextPropertyResolver.java new file mode 100644 index 00000000000..d3c4cd04f93 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ContextPropertyResolver.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.OptionalLong; + +public class ContextPropertyResolver implements PropertyResolver { + private final PropertyResolver delegate; + private final String context; + + public ContextPropertyResolver(final PropertyResolver delegate, final String context) { + this.delegate = delegate; + this.context = context; + } + + @Override + public void addSource(final PropertySource source) { + throw new UnsupportedOperationException("Cannot modify ContextPropertyResolver view"); + } + + @Override + public boolean hasProperty(final String key) { + return hasProperty(context, key); + } + + @Override + public boolean hasProperty(final String context, final String key) { + return delegate.hasProperty(context, key); + } + + @Override + public Optional getString(final String key) { + return getString(context, key); + } + + @Override + public Optional getString(final String context, final String key) { + return delegate.getString(context, key); + } + + @Override + public List getList(final String key) { + return getList(context, key); + } + + @Override + public List getList(final String context, final String key) { + return delegate.getList(context, key); + } + + @Override + public boolean getBoolean(final String key) { + return getBoolean(context, key); + } + + @Override + public boolean getBoolean(final String key, final boolean defaultValue) { + return getBoolean(context, key, defaultValue); + } + + @Override + public boolean getBoolean(final String context, final String key, final boolean defaultValue) { + return delegate.getBoolean(context, key, defaultValue); + } + + @Override + public boolean getBoolean(final String key, final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return getBoolean(context, key, defaultValueIfAbsent, defaultValueIfPresent); + } + + @Override + public boolean getBoolean(final String context, final String key, final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return delegate.getBoolean(context, key, defaultValueIfAbsent, defaultValueIfPresent); + } + + @Override + public OptionalInt getInt(final String key) { + return getInt(context, key); + } + + @Override + public OptionalInt getInt(final String context, final String key) { + return delegate.getInt(context, key); + } + + @Override + public OptionalLong getLong(final String key) { + return getLong(context, key); + } + + @Override + public OptionalLong getLong(final String context, final String key) { + return delegate.getLong(context, key); + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/DefaultPropertyResolver.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/DefaultPropertyResolver.java new file mode 100644 index 00000000000..d41a2efb198 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/DefaultPropertyResolver.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +public class DefaultPropertyResolver implements PropertyResolver { + + private final Set sources = new ConcurrentSkipListSet<>(new PropertySource.Comparator()); + + @Override + public void addSource(final PropertySource source) { + sources.add(source); + } + + @Override + public boolean hasProperty(final String context, final String key) { + return sources.stream().anyMatch(source -> source.containsProperty(context, key)) || + notDefaultContext(context) && sources.stream() + .anyMatch(source -> source.containsProperty(DEFAULT_CONTEXT, key)); + } + + @Override + public Optional getString(final String context, final String key) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getProperty(context, key)); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getProperty(DEFAULT_CONTEXT, key)); + } + + @Override + public List getList(final String context, final String key) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getList(context, key)) + .orElseGet(List::of); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getList(DEFAULT_CONTEXT, key)) + .orElseGet(List::of); + } + + @Override + public boolean getBoolean(final String context, final String key, final boolean defaultValue) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getBoolean(context, key)) + .orElse(BooleanProperty.ABSENT) + .orElse(defaultValue); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getBoolean(DEFAULT_CONTEXT, key)) + .orElse(BooleanProperty.ABSENT) + .orElse(defaultValue); + } + + @Override + public boolean getBoolean(final String context, final String key, + final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getBoolean(context, key)) + .orElse(BooleanProperty.ABSENT) + .orElse(defaultValueIfAbsent, defaultValueIfPresent); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getBoolean(DEFAULT_CONTEXT, key)) + .orElse(BooleanProperty.ABSENT) + .orElse(defaultValueIfAbsent, defaultValueIfPresent); + } + + @Override + public OptionalInt getInt(final String context, final String key) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getInt(context, key)) + .orElseGet(OptionalInt::empty); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getInt(DEFAULT_CONTEXT, key)) + .orElseGet(OptionalInt::empty); + } + + @Override + public OptionalLong getLong(final String context, final String key) { + if (notDefaultContext(context)) { + final Optional foundSource = findSourceWithProperty(context, key); + if (foundSource.isPresent()) { + return foundSource + .map(source -> source.getLong(context, key)) + .orElseGet(OptionalLong::empty); + } + } + return findSourceWithProperty(DEFAULT_CONTEXT, key) + .map(source -> source.getLong(context, key)) + .orElseGet(OptionalLong::empty); + } + + private Optional findSourceWithProperty(final String context, final String key) { + return sources.stream() + .filter(source -> source.containsProperty(context, key)) + .findFirst(); + } + + private static boolean notDefaultContext(final String context) { + return context != null && !context.equals(DEFAULT_CONTEXT); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecycler.java similarity index 87% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecycler.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecycler.java index 8936a8a682c..b8e6699c3c9 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecycler.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecycler.java @@ -14,10 +14,15 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.util.function.Supplier; +/** + * Recycler strategy which doesn't recycle anything; all instances are freshly created. + * + * @param the recyclable type + */ public class DummyRecycler implements Recycler { private final Supplier supplier; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecyclerFactory.java similarity index 95% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecyclerFactory.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecyclerFactory.java index 2a96d98fb84..2430efecf3f 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/DummyRecyclerFactory.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/DummyRecyclerFactory.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.util.function.Consumer; import java.util.function.Supplier; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonReader.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/JsonReader.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonReader.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/JsonReader.java index 37dc60eaebb..1d292b7cb5d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonReader.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/JsonReader.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.util; import java.math.BigDecimal; import java.math.BigInteger; @@ -46,6 +46,7 @@ * This code is heavily influenced by the reader of * mjson. */ +@InternalApi public final class JsonReader { private enum Delimiter { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/JsonResourcePropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/JsonResourcePropertySource.java new file mode 100644 index 00000000000..81fd0014c5a --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/JsonResourcePropertySource.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class JsonResourcePropertySource implements PropertySource { + + public static JsonResourcePropertySource fromUrl(final URL url, final int priority) { + final String json; + try (final InputStream in = url.openStream()) { + final byte[] bytes = in.readAllBytes(); + // JSON is defined as UTF-8 which is convenient + json = new String(bytes, StandardCharsets.UTF_8); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + final Object read = JsonReader.read(json); + if (!(read instanceof Map)) { + throw new IllegalArgumentException("Expected JSON object key " + ROOT_KEY + " from " + url); + } + final Object root = ((Map) read).get(ROOT_KEY); + if (!(root instanceof Map)) { + throw new IllegalArgumentException("Expected map in " + ROOT_KEY + " from " + url); + } + return new JsonResourcePropertySource(Cast.cast(root), priority); + } + + public static final String ROOT_KEY = "log4j2"; + private static final Pattern COMPOSITE_KEY = Pattern.compile("log4j2\\.(?[^.]+)\\.(?[^.]+)\\.(?.+)"); + private final Map data; + private final int priority; + + private JsonResourcePropertySource(final Map data, final int priority) { + this.priority = priority; + Objects.requireNonNull(data); + this.data = data; + } + + @Override + public int getPriority() { + return priority; + } + + @Override + public String getProperty(final String key) { + return getString(splitCompositeKey(key)); + } + + @Override + public String getProperty(final String context, final String key) { + return getString(splitKey(context, key)); + } + + @Override + public List getList(final String context, final String key) { + final Object value = lookup(splitKey(context, key)); + if (value instanceof String) { + return List.of(Strings.splitList((String) value)); + } + if (value instanceof List) { + return Cast.cast(value); + } + return List.of(); + } + + @Override + public BooleanProperty getBoolean(final String context, final String key) { + if (hasProperty(splitKey(context, key))) { + final Object value = lookup(splitKey(context, key)); + if (value instanceof Boolean) { + return (boolean) value ? BooleanProperty.TRUE : BooleanProperty.FALSE; + } + if (value instanceof String) { + return BooleanProperty.parse((String) value); + } + return BooleanProperty.PRESENT; + } + return BooleanProperty.ABSENT; + } + + @Override + public OptionalInt getInt(final String context, final String key) { + final Object value = lookup(splitKey(context, key)); + if (value instanceof Number) { + return OptionalInt.of(((Number) value).intValue()); + } + if (value instanceof String) { + try { + final int i = Integer.parseInt((String) value); + return OptionalInt.of(i); + } catch (final NumberFormatException ignored) { + } + } + return OptionalInt.empty(); + } + + @Override + public OptionalLong getLong(final String context, final String key) { + final Object value = lookup(splitKey(context, key)); + if (value instanceof Number) { + return OptionalLong.of(((Number) value).longValue()); + } + if (value instanceof String) { + try { + final long i = Long.parseLong((String) value); + return OptionalLong.of(i); + } catch (final NumberFormatException ignored) { + } + } + return OptionalLong.empty(); + } + + private String getString(final String[] path) { + final Object value = lookup(path); + if (value instanceof String) { + return (String) value; + } + if (value instanceof Number || value instanceof Boolean) { + return value.toString(); + } + return null; + } + + @Override + public boolean containsProperty(final String key) { + return hasProperty(splitCompositeKey(key)); + } + + @Override + public boolean containsProperty(final String context, final String key) { + return hasProperty(splitKey(context, key)); + } + + private boolean hasProperty(final String[] path) { + Object value = data; + for (final String key : path) { + if (value instanceof Map) { + final Map map = Cast.cast(value); + if (!map.containsKey(key)) { + return false; + } + value = map.get(key); + } else { + return false; + } + } + return true; + } + + private Object lookup(final String[] path) { + Object value = data; + for (final String key : path) { + if (value instanceof Map) { + final Map map = Cast.cast(value); + value = map.get(key); + } else { + return null; + } + } + return value; + } + + private static String[] splitCompositeKey(final String key) { + final Matcher matcher = COMPOSITE_KEY.matcher(key); + if (matcher.matches()) { + final String[] parts = new String[3]; + parts[0] = matcher.group("context"); + parts[1] = matcher.group("component"); + parts[2] = matcher.group("key"); + return parts; + } + throw new IllegalArgumentException("Invalid key: " + key); + } + + private static String[] splitKey(final String context, final String key) { + final String[] parts = splitCompositeKey(key); + assert context != null; + parts[0] = context; + return parts; + } +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java index 0150aaf289a..4a3a639b938 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java @@ -138,11 +138,8 @@ public T value() { return unwrapNull(currentValue); } final T newValue = supplier.get(); - if (VALUE.compareAndExchangeRelease(this, null, wrapNull(newValue)) == null) { - return newValue; - } - final Object value = VALUE.getAcquire(this); - return unwrapNull(value); + final Object witness = VALUE.compareAndExchangeRelease(this, null, wrapNull(newValue)); + return witness == null ? newValue : unwrapNull(witness); } @Override diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java index 14c4af7dd8c..73887419725 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java @@ -26,6 +26,7 @@ import java.util.LinkedHashSet; import java.util.Objects; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; /** @@ -43,14 +44,10 @@ public final class LoaderUtil { private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); - // this variable must be lazily loaded; otherwise, we get a nice circular class loading problem where LoaderUtil - // wants to use PropertiesUtil, but then PropertiesUtil wants to use LoaderUtil. - private static Boolean ignoreTCCL; - + private static final PrivilegedAction IS_FORCE_THREAD_CONTEXT_CLASS_LOADER_ONLY = + () -> Boolean.getBoolean(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER); private static final boolean GET_CLASS_LOADER_DISABLED; - protected static Boolean forceTcclOnly; - private static final PrivilegedAction TCCL_GETTER = new ThreadContextClassLoaderGetter(); static { @@ -294,51 +291,19 @@ public static T newCheckedInstanceOf(final String className, final Class return newInstanceOf(loadClass(className).asSubclass(clazz)); } - /** - * Loads and instantiates a class given by a property name. - * - * @param propertyName The property name to look up a class name for. - * @param clazz The class to cast it to. - * @param The type to cast it to. - * @return new instance of the class given in the property or {@code null} if the property was unset. - * @throws ClassNotFoundException if the class isn't available to the usual ClassLoaders - * @throws IllegalAccessException if the class can't be instantiated through a public constructor - * @throws InstantiationException if there was an exception whilst instantiating the class - * @throws InvocationTargetException if there was an exception whilst constructing the class - * @throws ClassCastException if the constructed object isn't type compatible with {@code T} - * @since 2.5 - */ - public static T newCheckedInstanceOfProperty(final String propertyName, final Class clazz) - throws ClassNotFoundException, InvocationTargetException, InstantiationException, - IllegalAccessException { - final String className = PropertiesUtil.getProperties().getStringProperty(propertyName); - if (className == null) { - return null; - } - return newCheckedInstanceOf(className, clazz); - } - private static boolean isIgnoreTccl() { - // we need to lazily initialize this, but concurrent access is not an issue - if (ignoreTCCL == null) { - final String ignoreTccl = PropertiesUtil.getProperties().getStringProperty(LoggingSystemProperties.LOADER_IGNORE_THREAD_CONTEXT_LOADER, null); - ignoreTCCL = ignoreTccl != null && !"false".equalsIgnoreCase(ignoreTccl.trim()); - } - return ignoreTCCL; + return LoggingSystem.getPropertyResolver() + .getBoolean(LoggingSystemProperties.LOADER_IGNORE_THREAD_CONTEXT_LOADER, false, true); } - private static boolean isForceTccl() { - if (forceTcclOnly == null) { - // PropertiesUtil.getProperties() uses that code path so don't use that! - try { - forceTcclOnly = System.getSecurityManager() == null ? - Boolean.getBoolean(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER) : - AccessController.doPrivileged((PrivilegedAction) () -> Boolean.getBoolean(LoggingSystemProperties.LOADER_FORCE_THREAD_CONTEXT_LOADER)); - } catch (final SecurityException se) { - forceTcclOnly = false; - } + static boolean isForceTccl() { + // used by LoaderUtil::findResources/findUrlResources -> LoggingSystem::loadPropertySources -> PropertyResolver initialization + try { + return System.getSecurityManager() == null ? IS_FORCE_THREAD_CONTEXT_CLASS_LOADER_ONLY.run() : + AccessController.doPrivileged(IS_FORCE_THREAD_CONTEXT_CLASS_LOADER_ONLY); + } catch (final SecurityException ignored) { + return false; } - return forceTcclOnly; } /** @@ -371,7 +336,7 @@ public static Collection findResources(final String resource, final boolean public static Collection findUrlResources(final String resource, boolean useTccl) { // @formatter:off final ClassLoader[] candidates = { - getThreadContextClassLoader(), + useTccl ? getThreadContextClassLoader() : null, isForceTccl() ? null : LoaderUtil.class.getClassLoader(), isForceTccl() || GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()}; // @formatter:on diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java index 643e52b7348..9aaedf41007 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java @@ -29,6 +29,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; +import org.apache.logging.log4j.spi.LoggingSystem; + /** * Consider this class private. *

@@ -87,15 +89,13 @@ private PropertiesUtil(final String propertiesFileName, final boolean useTccl) { * Returns the PropertiesUtil used by Log4j. * * @return the main Log4j PropertiesUtil instance. + * @deprecated use {@link LoggingSystem#getPropertyResolver()} */ + @Deprecated public static PropertiesUtil getProperties() { return COMPONENT_PROPERTIES.value(); } - public static PropertyEnvironment getProperties(final String namespace) { - return new Environment(new PropertyFilePropertySource(String.format("log4j2.%s.properties", namespace))); - } - public static ResourceBundle getCharsetsResourceBundle() { return ResourceBundle.getBundle("Log4j-charsets"); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java new file mode 100644 index 00000000000..8a0226d9f02 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.OptionalLong; + +public interface PropertyResolver { + + String DEFAULT_CONTEXT = PropertySource.DEFAULT_CONTEXT; + + void addSource(final PropertySource source); + + default boolean hasProperty(final String key) { + return hasProperty(DEFAULT_CONTEXT, key); + } + + boolean hasProperty(final String context, final String key); + + default Optional getString(final String key) { + return getString(DEFAULT_CONTEXT, key); + } + + Optional getString(final String context, final String key); + + default List getList(final String key) { + return getList(DEFAULT_CONTEXT, key); + } + + List getList(final String context, final String key); + + default boolean getBoolean(final String key) { + return getBoolean(DEFAULT_CONTEXT, key); + } + + default boolean getBoolean(final String context, final String key) { + return getBoolean(context, key, false); + } + + default boolean getBoolean(final String key, final boolean defaultValue) { + return getBoolean(DEFAULT_CONTEXT, key, defaultValue); + } + + boolean getBoolean(final String context, final String key, final boolean defaultValue); + + default boolean getBoolean(final String key, + final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { + return getBoolean(DEFAULT_CONTEXT, key, defaultValueIfAbsent, defaultValueIfPresent); + } + + boolean getBoolean(final String context, final String key, + final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent); + + default OptionalInt getInt(final String key) { + return getInt(DEFAULT_CONTEXT, key); + } + + OptionalInt getInt(final String context, final String key); + + default OptionalLong getLong(final String key) { + return getLong(DEFAULT_CONTEXT, key); + } + + OptionalLong getLong(final String context, final String key); +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java index 4a3e29f0741..f3de116641f 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java @@ -24,16 +24,25 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * A source for global configuration properties. + * A source for global and LoggerContext configuration properties. * * @since 2.10.0 */ public interface PropertySource { + /** + * Constant value for the name used to represent the default context for providing default settings for + * LoggerContext properties along with default values for global properties. + * + * @since 3.0.0 + */ + String DEFAULT_CONTEXT = "*"; /** * Returns the order in which this PropertySource has priority. A higher value means that the source will be @@ -48,14 +57,16 @@ public interface PropertySource { * * @param action action to perform on each key/value pair */ + @Deprecated(since = "3.0.0") default void forEach(final BiConsumer action) { } /** * Returns the list of all property names. - * + * * @return list of property names */ + @Deprecated(since = "3.0.0") default Collection getPropertyNames() { return Collections.emptySet(); } @@ -67,6 +78,7 @@ default Collection getPropertyNames() { * @param tokens list of property name tokens * @return a normalized property name using the given tokens */ + @Deprecated(since = "3.0.0") default CharSequence getNormalForm(final Iterable tokens) { return null; } @@ -81,6 +93,43 @@ default String getProperty(final String key) { return null; } + default String getProperty(final String context, final String key) { + final String compositeKey = isDefaultContext(context) ? key : compositeKey(context, key); + return getProperty(compositeKey); + } + + default List getList(final String context, final String key) { + final String value = getProperty(context, key); + return List.of(Strings.splitList(value)); + } + + default BooleanProperty getBoolean(final String context, final String key) { + return BooleanProperty.parse(getProperty(context, key)); + } + + default OptionalInt getInt(final String context, final String key) { + final String value = getProperty(context, key); + if (value != null) { + try { + final int i = Integer.parseInt(value); + return OptionalInt.of(i); + } catch (final NumberFormatException ignored) { + } + } + return OptionalInt.empty(); + } + + default OptionalLong getLong(final String context, final String key) { + final String value = getProperty(context, key); + if (value != null) { + try { + final long i = Long.parseLong(value); + return OptionalLong.of(i); + } catch (final NumberFormatException ignored) { + } + } + return OptionalLong.empty(); + } /** * For PropertySources that cannot iterate over all the potential properties this provides a direct lookup. @@ -92,6 +141,24 @@ default boolean containsProperty(final String key) { return false; } + default boolean containsProperty(final String context, final String key) { + return isDefaultContext(context) ? + containsProperty(key) : + containsProperty(compositeKey(context, key)); + } + + private static boolean isDefaultContext(final String context) { + return context == null || context.equals(DEFAULT_CONTEXT); + } + + private static String compositeKey(final String context, final String key) { + final int i = key.indexOf('*'); + if (i == -1 || i + 1 == key.length()) { + return "log4j2." + context + '.' + key; + } + return key.substring(0, i) + context + key.substring(i + 1); + } + /** * Comparator for ordering PropertySource instances by priority. * @@ -107,10 +174,9 @@ public int compare(final PropertySource o1, final PropertySource o2) { } /** - * Utility methods useful for PropertySource implementations. - * - * @since 2.10.0 + * @deprecated no longer needed by PropertySource */ + @Deprecated(since = "3.0.0") final class Util { private static final Pattern PREFIX_PATTERN = Pattern.compile( // just lookahead for AsyncLogger diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java similarity index 89% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java index b83ae2f3033..5f1bbc6b44f 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java @@ -14,12 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.util.Queue; import java.util.function.Consumer; import java.util.function.Supplier; +/** + * Recycling strategy that uses an internal queue to maintain a maximum number of unused recyclable instances. + * + * @param the recycling type + */ public class QueueingRecycler implements Recycler { private final Supplier supplier; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java similarity index 89% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java index 85b04ab7e3c..3967cad179b 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.util.Queue; import java.util.function.Consumer; @@ -32,8 +32,7 @@ public QueueingRecyclerFactory(final Supplier> queueSupplier) { public Recycler create( final Supplier supplier, final Consumer cleaner) { - @SuppressWarnings("unchecked") - final Queue queue = (Queue) queueSupplier.get(); + final Queue queue = Cast.cast(queueSupplier.get()); return new QueueingRecycler<>(supplier, cleaner, queue); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java new file mode 100644 index 00000000000..1a41b03827d --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +/** + * Strategy for recycling objects. This is primarily useful for heavyweight objects and buffers. + * + * @param the recyclable type + * @since 3.0.0 + */ +public interface Recycler { + + /** + * Acquires an instance of V. This may either be a fresh instance of V or a recycled instance of V. + * Recycled instances will be modified by their cleanup function before being returned. + * + * @return an instance of V to be used + */ + V acquire(); + + /** + * Releases an instance of V. This allows the instance to be recycled and later reacquired for new + * purposes. + * + * @param value an instance of V no longer being used + */ + void release(V value); + +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java similarity index 77% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java index 2b4d236758f..65a5ed403a0 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -25,7 +25,8 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.function.Supplier; -import org.apache.logging.log4j.util.LoaderUtil; +import org.apache.logging.log4j.spi.InstanceFactory; +import org.apache.logging.log4j.spi.LoggingSystem; import org.jctools.queues.MpmcArrayQueue; import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; @@ -34,21 +35,46 @@ public final class RecyclerFactories { private RecyclerFactories() {} - private static final String JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH = - "org.jctools.queues.MpmcArrayQueue.new"; + private static final String JCTOOLS_FACTORY_CLASS_NAME = + RecyclerFactories.class.getName() + "$MpmcArrayQueueFactory"; - private static final boolean JCTOOLS_QUEUE_CLASS_AVAILABLE = - isJctoolsQueueClassAvailable(); + private interface QueueFactory { + Queue create(final int capacity); + } + + private static class ArrayBlockingQueueFactory implements QueueFactory { + @Override + public Queue create(final int capacity) { + return new ArrayBlockingQueue<>(capacity); + } + } + + @SuppressWarnings("unused") // loaded via reflection to check for presence of JCTools + private static class MpmcArrayQueueFactory implements QueueFactory { + @Override + public Queue create(final int capacity) { + return new MpmcArrayQueue<>(capacity); + } + } + + private static Supplier> getQueueSupplier(final int capacity) { - private static boolean isJctoolsQueueClassAvailable() { + final ClassLoader classLoader = RecyclerFactories.class.getClassLoader(); + Class factoryClass; try { - final String className = JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH - .replaceAll("\\.new$", ""); - LoaderUtil.loadClass(className); - return true; - } catch (final ClassNotFoundException ignored) { - return false; + // try to load RecyclerFactories.MpmcArrayQueueFactory; a linkage error should occur if JCTools is unavailable + factoryClass = classLoader.loadClass(JCTOOLS_FACTORY_CLASS_NAME) + .asSubclass(QueueFactory.class); + } catch (final ClassNotFoundException | LinkageError ignored) { + factoryClass = ArrayBlockingQueueFactory.class; } + + final LoggingSystem system = LoggingSystem.getInstance(); + final InstanceFactory instanceFactory = system.getInstanceFactory(); + final QueueFactory queueFactory = instanceFactory.getInstance(factoryClass); + + return () -> queueFactory.create(capacity); + } public static RecyclerFactory ofSpec(final String recyclerFactorySpec) { @@ -63,11 +89,7 @@ public static RecyclerFactory ofSpec(final String recyclerFactorySpec) { if (isThreadLocalsEnabled()) { return ThreadLocalRecyclerFactory.getInstance(); } else { - final Supplier> queueSupplier = - JCTOOLS_QUEUE_CLASS_AVAILABLE - ? () -> new MpmcArrayQueue<>(defaultCapacity) - : () -> new ArrayBlockingQueue<>(defaultCapacity); - return new QueueingRecyclerFactory(queueSupplier); + return new QueueingRecyclerFactory(getQueueSupplier(defaultCapacity)); } } @@ -113,9 +135,7 @@ private static RecyclerFactory readQueueingRecyclerFactory( final StringParameterParser.Value supplierValue = parsedValues.get("supplier"); final String supplierPath; if (supplierValue == null || supplierValue instanceof StringParameterParser.NullValue) { - supplierPath = JCTOOLS_QUEUE_CLASS_AVAILABLE - ? JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH - : "java.util.concurrent.ArrayBlockingQueue.new"; + supplierPath = null; } else { supplierPath = supplierValue.toString(); } @@ -136,6 +156,9 @@ private static RecyclerFactory readQueueingRecyclerFactory( } // Execute the read spec. + if (supplierPath == null) { + return new QueueingRecyclerFactory(getQueueSupplier(capacity)); + } return createRecyclerFactory(queueFactorySpec, supplierPath, capacity); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java new file mode 100644 index 00000000000..eab78a702d3 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Factory for {@link Recycler} strategies. Depending on workloads, different instance recycling strategies may be + * most performant. For example, traditional multithreaded workloads may benefit from using thread-local instance + * recycling while different models of concurrency or versions of the JVM may benefit from using an object pooling + * strategy instead. + * + * @since 3.0.0 + */ +@FunctionalInterface +public interface RecyclerFactory { + + /** + * Creates a new recycler using the given supplier function for initial instances. These instances have + * no cleaner function and are assumed to always be reusable. + * + * @param supplier function to provide new instances of a recyclable object + * @param the recyclable type + * @return a new recycler for V-type instances + */ + default Recycler create(final Supplier supplier) { + return create(supplier, ignored -> {}); + } + + /** + * Creates a new recycler using the given functions for providing fresh instances and for cleaning up + * existing instances for reuse. For example, a StringBuilder recycler would provide two functions: + * a supplier function for constructing a new StringBuilder with a preselected initial capacity and + * another function for trimming the StringBuilder to some preselected maximum capacity and setting + * its length back to 0 as if it were a fresh StringBuilder. + * + * @param supplier function to provide new instances of a recyclable object + * @param cleaner function to reset a recyclable object to a fresh state + * @param the recyclable type + * @return a new recycler for V-type instances + */ + Recycler create(Supplier supplier, Consumer cleaner); + +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java index fe549822c95..5f092e3d6c6 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java @@ -27,13 +27,9 @@ */ @InternalApi public final class StackLocatorUtil { - private static StackLocator stackLocator = null; + private static final StackLocator stackLocator = StackLocator.getInstance(); private static volatile boolean errorLogged; - static { - stackLocator = StackLocator.getInstance(); - } - private StackLocatorUtil() { } diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java similarity index 99% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java index c2333a588eb..653877c1f49 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java @@ -14,9 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; - -import org.apache.logging.log4j.util.Strings; +package org.apache.logging.log4j.util; import java.util.Collections; import java.util.LinkedHashMap; @@ -25,6 +23,8 @@ import java.util.Set; import java.util.concurrent.Callable; +import org.apache.logging.log4j.util.Strings; + public final class StringParameterParser { private StringParameterParser() {} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java index b3d1c3ccdfd..6f0e5a31b0c 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.util; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collection; import java.util.Objects; import java.util.Properties; @@ -32,18 +34,33 @@ public class SystemPropertiesPropertySource implements PropertySource { private static final int DEFAULT_PRIORITY = 0; private static final String PREFIX = "log4j2."; + private static final PrivilegedAction GET_SYSTEM_PROPERTIES = System::getProperties; + + private static PrivilegedAction getSystemPropertyAction(final String key) { + return () -> System.getProperty(key); + } + + private static PrivilegedAction getSystemPropertyAction(final String key, final String defaultKey) { + return () -> System.getProperty(key, defaultKey); + } + /** * Used by bootstrap code to get system properties without loading PropertiesUtil. */ public static String getSystemProperty(final String key, final String defaultValue) { try { - return System.getProperty(key, defaultValue); - } catch (SecurityException e) { + return System.getSecurityManager() == null ? + System.getProperty(key, defaultValue) : + AccessController.doPrivileged(getSystemPropertyAction(key, defaultValue)); + } catch (SecurityException ignored) { // Silently ignore the exception return defaultValue; } } + private final SystemProperties systemProperties = new DefaultSystemProperties(); + private final SystemProperties securedProperties = new AccessControlledSystemProperties(); + @Override public int getPriority() { return DEFAULT_PRIORITY; @@ -51,17 +68,7 @@ public int getPriority() { @Override public void forEach(final BiConsumer action) { - final Properties properties; - try { - properties = System.getProperties(); - } catch (final SecurityException e) { - // (1) There is no status logger. - // (2) LowLevelLogUtil also consults system properties ("line.separator") to - // open a BufferedWriter, so this may fail as well. Just having a hard reference - // in this code to LowLevelLogUtil would cause a problem. - // (3) We could log to System.err (nah) or just be quiet as we do now. - return; - } + final Properties properties = getSystemProperties().getProperties(); // Lock properties only long enough to get a thread-safe SAFE snapshot of its // current keys, an array. final Object[] keySet; @@ -83,20 +90,12 @@ public CharSequence getNormalForm(final Iterable tokens) @Override public Collection getPropertyNames() { - try { - return System.getProperties().stringPropertyNames(); - } catch (final SecurityException e) { - return PropertySource.super.getPropertyNames(); - } + return getSystemProperties().getProperties().stringPropertyNames(); } @Override public String getProperty(String key) { - try { - return System.getProperty(key); - } catch (final SecurityException e) { - return PropertySource.super.getProperty(key); - } + return getSystemProperties().getProperty(key); } @Override @@ -104,4 +103,79 @@ public boolean containsProperty(String key) { return getProperty(key) != null; } + private SystemProperties getSystemProperties() { + return System.getSecurityManager() == null ? systemProperties : securedProperties; + } + + private interface SystemProperties { + Properties getProperties(); + + String getProperty(String key); + + String getProperty(String key, String defaultValue); + } + + private static class DefaultSystemProperties implements SystemProperties { + @Override + public Properties getProperties() { + try { + return System.getProperties(); + } catch (final SecurityException ignored) { + return new Properties(); + } + } + + @Override + public String getProperty(final String key) { + try { + return System.getProperty(key); + } catch (final SecurityException ignored) { + return null; + } + } + + @Override + public String getProperty(final String key, final String defaultValue) { + try { + return System.getProperty(key, defaultValue); + } catch (final SecurityException ignored) { + return defaultValue; + } + } + } + + private static class AccessControlledSystemProperties implements SystemProperties { + @Override + public Properties getProperties() { + try { + return AccessController.doPrivileged(GET_SYSTEM_PROPERTIES); + } catch (final SecurityException ignored) { + // (1) There is no status logger. + // (2) LowLevelLogUtil also consults system properties ("line.separator") to + // open a BufferedWriter, so this may fail as well. Just having a hard reference + // in this code to LowLevelLogUtil would cause a problem. + // (3) We could log to System.err (nah) or just be quiet as we do now. + return new Properties(); + } + } + + @Override + public String getProperty(final String key) { + try { + return AccessController.doPrivileged(getSystemPropertyAction(key)); + } catch (final SecurityException ignored) { + return null; + } + } + + @Override + public String getProperty(final String key, final String defaultValue) { + try { + return AccessController.doPrivileged(getSystemPropertyAction(key, defaultValue)); + } catch (final SecurityException ignored) { + return defaultValue; + } + } + } + } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java new file mode 100644 index 00000000000..5401891b56a --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Recycling strategy that caches instances in a ThreadLocal value to allow threads to reuse objects. This strategy + * may not be appropriate in workloads where units of work are independent of operating system threads such as + * reactive streams, coroutines, or virtual threads. + * + * @param the recyclable type + */ +public class ThreadLocalRecycler implements Recycler { + + private final Supplier supplier; + private final Consumer cleaner; + + private final ThreadLocal holder; + private final boolean referenceCountingEnabled; + private final ThreadLocal activeReferenceCount = ThreadLocal.withInitial(AtomicInteger::new); + + public ThreadLocalRecycler( + final Supplier supplier, + final Consumer cleaner) { + this(supplier, cleaner, false); + } + + public ThreadLocalRecycler( + final Supplier supplier, + final Consumer cleaner, + final boolean referenceCountingEnabled) { + this.supplier = supplier; + this.cleaner = cleaner; + this.holder = ThreadLocal.withInitial(supplier); + this.referenceCountingEnabled = referenceCountingEnabled; + } + + @Override + public V acquire() { + final V value; + if (referenceCountingEnabled) { + final AtomicInteger count = activeReferenceCount.get(); + if (count.compareAndSet(0, 1)) { + value = holder.get(); + } else { + count.incrementAndGet(); + value = supplier.get(); + } + } else { + value = holder.get(); + } + cleaner.accept(value); + return value; + } + + @Override + public void release(final V value) { + if (referenceCountingEnabled) { + activeReferenceCount.get().decrementAndGet(); + } + } + + // Visible for testing + int getActiveReferenceCount() { + return activeReferenceCount.get().get(); + } + +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java similarity index 95% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java rename to log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java index 048262cf4e0..c877b4d24b7 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; import java.util.function.Consumer; import java.util.function.Supplier; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java index 3c5907bb9ff..9774da48989 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java @@ -17,6 +17,7 @@ package org.apache.logging.log4j.util; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.status.StatusLogger; @@ -51,7 +52,7 @@ public class Unbox { private static final Logger LOGGER = StatusLogger.getLogger(); private static final int BITS_PER_INT = 32; private static final int RINGBUFFER_MIN_SIZE = 32; - private static final int RINGBUFFER_SIZE = calculateRingBufferSize(LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE); + private static final int RINGBUFFER_SIZE = calculateRingBufferSize(); private static final int MASK = RINGBUFFER_SIZE - 1; /** @@ -128,22 +129,16 @@ private Unbox() { // this is a utility } - private static int calculateRingBufferSize(final String propertyName) { - final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName, - String.valueOf(RINGBUFFER_MIN_SIZE)); - try { - int size = Integer.parseInt(userPreferredRBSize); - if (size < RINGBUFFER_MIN_SIZE) { - size = RINGBUFFER_MIN_SIZE; - LOGGER.warn("Invalid {} {}, using minimum size {}.", propertyName, userPreferredRBSize, - RINGBUFFER_MIN_SIZE); - } - return ceilingNextPowerOfTwo(size); - } catch (final Exception ex) { - LOGGER.warn("Invalid {} {}, using default size {}.", propertyName, userPreferredRBSize, - RINGBUFFER_MIN_SIZE); - return RINGBUFFER_MIN_SIZE; + private static int calculateRingBufferSize() { + int size = LoggingSystem.getPropertyResolver() + .getInt(LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE) + .orElse(RINGBUFFER_MIN_SIZE); + if (size < RINGBUFFER_MIN_SIZE) { + LOGGER.warn("Invalid {} {}, using minimum size {}.", + LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE, size, RINGBUFFER_MIN_SIZE); + size = RINGBUFFER_MIN_SIZE; } + return ceilingNextPowerOfTwo(size); } /** diff --git a/log4j-api/src/main/resources/META-INF/log4j2.default.component.json b/log4j-api/src/main/resources/META-INF/log4j2.default.component.json new file mode 100644 index 00000000000..832a29161bb --- /dev/null +++ b/log4j-api/src/main/resources/META-INF/log4j2.default.component.json @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +{ + "log4j2": { + "*": { + "GC": { + "enableThreadLocals": "calculate", + "unboxRingBufferSize": 32 + }, + "Message": { + "jsonFormatterMaxDepth": 8 + }, + "SimpleLogger": { + "showContextMap": false, + "showLogName": false, + "showShortLogName": true, + "showDateTime": false, + "dateTimeFormat": "yyyy/MM/dd HH:mm:ss:SSS zzz", + "logFile": "system.err", + "logLevel": "ERROR" + }, + "StatusLogger": { + "dateFormat": null, + "entries": 200, + "statusLoggerLevel": "WARN" + }, + "ThreadContext": { + "enabled": true, + "enableMap": true, + "enableStack": true, + "garbageFree": false, + "inheritable": false, + "initialCapacity": 16 + }, + "Web": { + "enableWebApp": "calculate" + } + } + } +} diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java index 8b316839ac9..b2b560993af 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java @@ -25,6 +25,7 @@ import org.apache.logging.log4j.core.net.SocketAddress; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginElement; @@ -96,6 +97,8 @@ public static class Builder> extends AbstractAppender.Build @PluginBuilderAttribute private boolean useClockForTimestampGenerator; + private Clock clock; + /** * Number of LogEvents to buffer before writing. Can be used with or without batch statements. */ @@ -103,7 +106,7 @@ public static class Builder> extends AbstractAppender.Build private int bufferSize; /** - * Whether or not to use batch statements when inserting records. + * Whether to use batch statements when inserting records. */ @PluginBuilderAttribute private boolean batched; @@ -159,6 +162,12 @@ public B setUseClockForTimestampGenerator(final boolean useClockForTimestampGene return asBuilder(); } + @Inject + public B setClock(final Clock clock) { + this.clock = clock; + return asBuilder(); + } + public B setBufferSize(final int bufferSize) { this.bufferSize = bufferSize; return asBuilder(); @@ -177,8 +186,8 @@ public B setBatchType(final BatchStatement.Type batchType) { @Override public CassandraAppender build() { final CassandraManager manager = CassandraManager.getManager(getName(), contactPoints, columns, useTls, - clusterName, keyspace, table, username, password, useClockForTimestampGenerator, bufferSize, batched, - batchType); + clusterName, keyspace, table, username, password, useClockForTimestampGenerator, clock, bufferSize, + batched, batchType); return new CassandraAppender(getName(), getFilter(), isIgnoreExceptions(), getPropertyArray(), manager); } diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java index 88f87d71693..9965536de65 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.cassandra; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import com.datastax.driver.core.BatchStatement; import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.Cluster; @@ -26,18 +31,13 @@ import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager; import org.apache.logging.log4j.core.appender.db.ColumnMapping; import org.apache.logging.log4j.core.net.SocketAddress; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; import org.apache.logging.log4j.spi.ThreadContextMap; import org.apache.logging.log4j.spi.ThreadContextStack; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.Strings; -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** * Manager for a Cassandra appender instance. */ @@ -87,7 +87,7 @@ protected void connectAndStart() { } @Override - protected void writeInternal(final LogEvent event, final Serializable serializable) { + protected void writeInternal(final LogEvent event, final Object serializable) { for (int i = 0; i < columnMappings.size(); i++) { final ColumnMapping columnMapping = columnMappings.get(i); if (ThreadContextMap.class.isAssignableFrom(columnMapping.getType()) @@ -121,11 +121,12 @@ public static CassandraManager getManager(final String name, final SocketAddress final ColumnMapping[] columns, final boolean useTls, final String clusterName, final String keyspace, final String table, final String username, final String password, - final boolean useClockForTimestampGenerator, final int bufferSize, + final boolean useClockForTimestampGenerator, final Clock clock, + final int bufferSize, final boolean batched, final BatchStatement.Type batchType) { return getManager(name, new FactoryData(contactPoints, columns, useTls, clusterName, keyspace, table, username, password, - useClockForTimestampGenerator, bufferSize, batched, batchType), CassandraManagerFactory.INSTANCE); + useClockForTimestampGenerator, bufferSize, clock, batched, batchType), CassandraManagerFactory.INSTANCE); } private static class CassandraManagerFactory implements ManagerFactory { @@ -144,7 +145,7 @@ public CassandraManager createManager(final String name, final FactoryData data) builder.withCredentials(data.username, data.password); } if (data.useClockForTimestampGenerator) { - builder.withTimestampGenerator(new ClockTimestampGenerator()); + builder.withTimestampGenerator(new ClockTimestampGenerator(data.clock)); } final Cluster cluster = builder.build(); @@ -182,13 +183,14 @@ private static class FactoryData extends AbstractFactoryData { private final String username; private final String password; private final boolean useClockForTimestampGenerator; + private final Clock clock; private final boolean batched; private final BatchStatement.Type batchType; private FactoryData(final SocketAddress[] contactPoints, final ColumnMapping[] columns, final boolean useTls, final String clusterName, final String keyspace, final String table, final String username, final String password, final boolean useClockForTimestampGenerator, final int bufferSize, - final boolean batched, final BatchStatement.Type batchType) { + final Clock clock, final boolean batched, final BatchStatement.Type batchType) { super(bufferSize, null); this.contactPoints = convertAndAddDefaultPorts(contactPoints); this.columns = columns; @@ -199,6 +201,7 @@ private FactoryData(final SocketAddress[] contactPoints, final ColumnMapping[] c this.username = username; this.password = password; this.useClockForTimestampGenerator = useClockForTimestampGenerator; + this.clock = clock; this.batched = batched; this.batchType = batchType; } diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java index cbc5c1fe888..88408360b0f 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java @@ -18,14 +18,17 @@ import com.datastax.driver.core.TimestampGenerator; import org.apache.logging.log4j.core.time.Clock; -import org.apache.logging.log4j.core.time.ClockFactory; /** * A {@link TimestampGenerator} implementation using the configured {@link Clock}. */ public class ClockTimestampGenerator implements TimestampGenerator { - private final Clock clock = ClockFactory.getClock(); + private final Clock clock; + + public ClockTimestampGenerator(final Clock clock) { + this.clock = clock; + } @Override public long next() { diff --git a/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java b/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java index 4f17e12e950..4cb42a92434 100644 --- a/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java +++ b/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java @@ -24,12 +24,14 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicReference; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; import org.apache.cassandra.service.CassandraDaemon; import org.apache.logging.log4j.core.util.Cancellable; import org.apache.logging.log4j.core.util.Closer; import org.apache.logging.log4j.core.util.Log4jThreadFactory; import org.apache.logging.log4j.core.util.Throwables; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.Constants; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; @@ -38,9 +40,6 @@ import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; import org.opentest4j.TestAbortedException; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Session; - import static org.junit.jupiter.api.Assertions.fail; public class CassandraExtension extends TypeBasedParameterResolver implements BeforeEachCallback, AfterEachCallback { @@ -122,7 +121,7 @@ private EmbeddedCassandra( @Override public void cancel() { // LOG4J2-1850 Cassandra on Windows calls System.exit in the daemon stop method - if (PropertiesUtil.getProperties().isOsWindows()) { + if (Constants.isWindows()) { cancelOnWindows(); } else { daemon.stop(); diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java index 1cd9f78d7b1..382e810741b 100644 --- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java @@ -16,32 +16,22 @@ */ package org.apache.logging.log4j.core.appender; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.containing; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - import java.io.IOException; import java.net.URL; +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.junit.WireMockRule; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration; -import org.apache.logging.log4j.jackson.json.layout.JsonLayout; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.core.test.net.ssl.TestConstants; +import org.apache.logging.log4j.jackson.json.layout.JsonLayout; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.status.StatusData; import org.apache.logging.log4j.status.StatusListener; @@ -50,8 +40,10 @@ import org.junit.Rule; import org.junit.Test; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; @Ignore("Fails often on Windows") @@ -129,13 +121,13 @@ public class HttpAppenderTest { private static final String LOG_MESSAGE = "Hello, world!"; - private static Log4jLogEvent createLogEvent() { - return Log4jLogEvent.newBuilder() + private static LogEvent createLogEvent() { + return LogEvent.builder() .setLoggerName(HttpAppenderTest.class.getName()) .setLoggerFqcn(HttpAppenderTest.class.getName()) .setLevel(Level.INFO) .setMessage(new SimpleMessage(LOG_MESSAGE)) - .build(); + .get(); } private final ResponseDefinitionBuilder SUCCESS_RESPONSE = aResponse().withStatus(201) @@ -183,14 +175,22 @@ public void testAppendHttps() throws Exception { wireMockRule.stubFor(post(urlEqualTo("/test/log4j/")) .willReturn(SUCCESS_RESPONSE)); + final TrustStoreConfiguration trustStoreConfiguration = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .setKeyStoreType(TestConstants.TRUSTSTORE_TYPE) + .build(); + final KeyStoreConfiguration keyStoreConfiguration = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .setKeyStoreType(TestConstants.KEYSTORE_TYPE) + .build(); final Appender appender = HttpAppender.newBuilder() .setName("Http") .setLayout(JsonLayout.createDefaultLayout()) .setConfiguration(ctx.getConfiguration()) .setUrl(new URL("https://localhost:" + wireMockRule.httpsPort() + "/test/log4j/")) - .setSslConfiguration(SslConfiguration.createSSLConfiguration(null, - KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), null, null, TestConstants.KEYSTORE_TYPE, null), - TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null ,null, TestConstants.TRUSTSTORE_TYPE, null))) + .setSslConfiguration(SslConfiguration.createSSLConfiguration(null, keyStoreConfiguration, trustStoreConfiguration)) .setVerifyHostname(false) .build(); appender.append(createLogEvent()); diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java index 1a24bcbe7cf..9773ef3c79d 100644 --- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java @@ -17,9 +17,7 @@ package org.apache.logging.log4j.core.appender; import java.io.IOException; -import java.io.OutputStream; import java.net.Socket; - import javax.net.ssl.SSLServerSocketFactory; import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer; @@ -29,24 +27,21 @@ import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; import org.apache.logging.log4j.core.net.ssl.StoreConfigurationException; -import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration; -import org.apache.logging.log4j.core.util.NullOutputStream; -import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.apache.logging.log4j.core.test.AvailablePortFinder; +import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Assume; import org.junit.ClassRule; import org.junit.Test; public class SecureSocketAppenderSocketOptionsTest { private static final int PORT; - private static TcpSocketTestServer tcpSocketTestServer; + private static final TcpSocketTestServer tcpSocketTestServer; private static SSLServerSocketFactory serverSocketFactory; - private static SslConfiguration sslConfiguration; static { PORT = AvailablePortFinder.getNextAvailable(); @@ -73,22 +68,15 @@ public static void afterClass() { } public static void initServerSocketFactory() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = KeyStoreConfiguration.createKeyStoreConfiguration( - TestConstants.KEYSTORE_FILE, // file - TestConstants.KEYSTORE_PWD(), // password - null, // passwordEnvironmentVariable - null, // passwordFile - null, // key store type - null); // algorithm - - final TrustStoreConfiguration tsc = TrustStoreConfiguration.createKeyStoreConfiguration( - TestConstants.TRUSTSTORE_FILE, // file - TestConstants.TRUSTSTORE_PWD(), // password - null, // passwordEnvironmentVariable - null, // passwordFile - null, // key store type - null); // algorithm - sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .build(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); + SslConfiguration sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc); serverSocketFactory = sslConfiguration.getSslServerSocketFactory(); } @@ -100,8 +88,6 @@ public void testSocketOptions() throws IOException { Assert.assertNotNull(appender); final TcpSocketManager manager = (TcpSocketManager) appender.getManager(); Assert.assertNotNull(manager); - final OutputStream outputStream = manager.getOutputStream(); - Assert.assertFalse(outputStream instanceof NullOutputStream); final SocketOptions socketOptions = manager.getSocketOptions(); Assert.assertNotNull(socketOptions); final Socket socket = manager.getSocket(); @@ -127,14 +113,4 @@ public void testSocketOptions() throws IOException { Assert.assertEquals(12345, socket.getSoLinger()); Assert.assertEquals(54321, socket.getSoTimeout()); } - - @Test - public void testSocketTrafficClass() throws IOException { - Assume.assumeTrue("Run only on Java 7", System.getProperty("java.specification.version").equals("1.7")); - Assume.assumeFalse("Do not run on Travis CI", "true".equals(System.getenv("TRAVIS"))); - final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class); - final TcpSocketManager manager = (TcpSocketManager) appender.getManager(); - final Socket socket = manager.getSocket(); - Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass()); - } } diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java index 0d1b9914367..36b04cf1534 100644 --- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java @@ -20,9 +20,9 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.apache.logging.log4j.core.test.AvailablePortFinder; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -61,12 +61,12 @@ public void teardown() { @Test public void testTcpAppenderDefaultEncoderBufferSize() throws Exception { - SocketAppenderTest.testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE); + SocketAppenderTest.testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } @Test public void testTcpAppenderLargeEncoderBufferSize() throws Exception { - SocketAppenderTest.testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE * 100); + SocketAppenderTest.testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize() * 100); } @Test diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java index bad65d4eeea..012007fe205 100644 --- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java @@ -26,7 +26,6 @@ import org.apache.logging.log4j.core.net.TcpSocketManager; import org.apache.logging.log4j.core.test.junit.AllocatePorts; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.core.util.NullOutputStream; import org.apache.logging.log4j.plugins.Named; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -64,8 +63,7 @@ public void testSocketOptions(@Named("socket") final SocketAppender appender) th .isInstanceOf(TcpSocketManager.class); final TcpSocketManager manager = (TcpSocketManager) abstractSocketManager; assertThat(manager.getOutputStream()) - .isNotNull() - .isInstanceOf(NullOutputStream.class); + .isNotNull(); final SocketOptions socketOptions = manager.getSocketOptions(); assertNotNull(socketOptions); final Socket socket = manager.getSocket(); diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java index 99fd2d08d76..f23cf35e349 100644 --- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java @@ -16,6 +16,21 @@ */ package org.apache.logging.log4j.core.appender; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + import com.fasterxml.jackson.databind.MappingIterator; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Level; @@ -25,10 +40,10 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.net.Protocol; import org.apache.logging.log4j.core.test.AvailablePortFinder; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.core.util.Throwables; import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; import org.apache.logging.log4j.jackson.json.layout.JsonLayout; @@ -39,21 +54,6 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - import static org.junit.jupiter.api.Assertions.*; /** @@ -112,13 +112,13 @@ static void reset() { @Test public void testTcpAppender1() throws Exception { - testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE); + testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } @Test @Disabled("WIP Bug when this method runs after testTcpAppender1()") public void testTcpAppender2() throws Exception { - testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE); + testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } static void testTcpAppender(final TcpSocketTestServer tcpTestServer, final Logger logger, final int bufferSize) @@ -310,7 +310,7 @@ public void run() { latch.countDown(); sock.receive(packet); count.incrementAndGet(); - final LogEvent event = objectMapper.readValue(packet.getData(), Log4jLogEvent.class); + final LogEvent event = objectMapper.readValue(packet.getData(), ImmutableLogEvent.class); queue.add(event); } } catch (final Throwable e) { @@ -374,7 +374,7 @@ public void run() { if (socket != null) { final InputStream is = socket.getInputStream(); while (!shutdown) { - final MappingIterator mappingIterator = objectMapper.readerFor(Log4jLogEvent.class).readValues(is); + final MappingIterator mappingIterator = objectMapper.readerFor(ImmutableLogEvent.class).readValues(is); while (mappingIterator.hasNextValue()) { queue.add(mappingIterator.nextValue()); count.incrementAndGet(); diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java index 4297dca4932..a08cdd72eff 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java @@ -33,7 +33,7 @@ public class BasicConfigurationFactory extends ConfigurationFactory { @Override public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) { - return new BasicConfiguration(); + return new BasicConfiguration(loggerContext); } @Override @@ -50,8 +50,8 @@ public static class BasicConfiguration extends AbstractConfiguration { private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level"; - public BasicConfiguration() { - super(null, ConfigurationSource.NULL_SOURCE); + public BasicConfiguration(final LoggerContext loggerContext) { + super(loggerContext, ConfigurationSource.NULL_SOURCE); final LoggerConfig root = getRootLogger(); final String name = System.getProperty(DEFAULT_LEVEL); diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java index 4910494856d..092fb459889 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.test.appender; -import java.io.Serializable; import java.nio.ByteBuffer; import org.apache.logging.log4j.core.Filter; @@ -37,7 +36,7 @@ public EncodingListAppender(final String name) { super(name); } - public EncodingListAppender(final String name, final Filter filter, final Layout layout, + public EncodingListAppender(final String name, final Filter filter, final Layout layout, final boolean newline, final boolean raw) { super(name, filter, layout, newline, raw); } @@ -69,7 +68,7 @@ public void writeBytes(final byte[] data, final int offset, final int length) { @Override public synchronized void append(final LogEvent event) { - final Layout layout = getLayout(); + final Layout layout = getLayout(); if (layout == null) { events.add(event); } else { diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java index 206afbc122a..3987a6d9dca 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java @@ -16,21 +16,20 @@ */ package org.apache.logging.log4j.core.test.appender; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.core.Appender; 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.core.config.plugins.PluginAttribute; -import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.util.Throwables; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.validation.constraints.Required; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; +import org.apache.logging.log4j.plugins.PluginAttribute; +import org.apache.logging.log4j.plugins.PluginFactory; /** * An {@link Appender} that fails on the first use and works for the rest. @@ -74,11 +73,8 @@ public synchronized List drainEvents() { } @PluginFactory - public static FailOnceAppender createAppender( - @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name, - @PluginAttribute("throwableClassName") final String throwableClassName) { - final Supplier throwableSupplier = createThrowableSupplier(name, throwableClassName); - return new FailOnceAppender(name, throwableSupplier); + public static Builder newBuilder() { + return new Builder(); } private static Supplier createThrowableSupplier( @@ -111,6 +107,24 @@ private static void stopCurrentThread() { Thread.currentThread().stop(); } + public static class Builder extends AbstractAppender.Builder implements Supplier { + private String throwableClassName; + + public String getThrowableClassName() { + return throwableClassName; + } + + public Builder setThrowableClassName(@PluginAttribute final String throwableClassName) { + this.throwableClassName = throwableClassName; + return this; + } + + @Override + public FailOnceAppender get() { + return new FailOnceAppender(getName(), createThrowableSupplier(getName(), getThrowableClassName())); + } + } + public enum ThrowableClassName {; public static final String RUNTIME_EXCEPTION = "RuntimeException"; diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java index 532a6b3d464..fe1d572986e 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java @@ -18,7 +18,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.Serializable; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender; @@ -31,7 +30,7 @@ */ public class InMemoryAppender extends AbstractOutputStreamAppender { - public InMemoryAppender(final String name, final Layout layout, final CompositeFilter filters, + public InMemoryAppender(final String name, final Layout layout, final CompositeFilter filters, final boolean ignoreExceptions, final boolean writeHeader, Property[] properties) { super(name, layout, filters, ignoreExceptions, true, properties, new InMemoryManager(name, layout, writeHeader)); } @@ -43,7 +42,7 @@ public String toString() { static class InMemoryManager extends OutputStreamManager { - public InMemoryManager(final String name, final Layout layout, + public InMemoryManager(final String name, final Layout layout, final boolean writeHeader) { super(new ByteArrayOutputStream(), name, layout, writeHeader); } diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java index aac8bbc912d..75621f435c6 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java @@ -16,6 +16,12 @@ */ package org.apache.logging.log4j.core.test.appender; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -32,13 +38,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - /** * This appender is primarily used for testing. Use in a real environment is discouraged as the List could eventually * grow to cause an OutOfMemoryError. @@ -69,7 +68,7 @@ public class ListAppender extends AbstractAppender { /** * CountDownLatch for asynchronous logging tests. Example usage: - * + * *

      * @Rule
      * public LoggerContextRule context = new LoggerContextRule("log4j-list.xml");
@@ -102,7 +101,7 @@ public ListAppender(final String name) {
         raw = false;
     }
 
-    public ListAppender(final String name, final Filter filter, final Layout layout,
+    public ListAppender(final String name, final Filter filter, final Layout layout,
             final boolean newline, final boolean raw) {
         super(name, filter, layout, true, Property.EMPTY_ARRAY);
         this.newLine = newline;
@@ -117,11 +116,11 @@ public ListAppender(final String name, final Filter filter, final Layout layout = getLayout();
+        final Layout layout = getLayout();
         if (layout == null) {
             if (event instanceof MutableLogEvent) {
                 // must take snapshot or subsequent calls to logger.log() will modify this event
-                events.add(((MutableLogEvent) event).createMemento());
+                events.add(event.copy());
             } else {
                 events.add(event);
             }
@@ -174,7 +173,7 @@ void write(final byte[] bytes) {
     public boolean stop(final long timeout, final TimeUnit timeUnit) {
         setStopping();
         super.stop(timeout, timeUnit, false);
-        final Layout layout = getLayout();
+        final Layout layout = getLayout();
         if (layout != null) {
             final byte[] bytes = layout.getFooter();
             if (bytes != null) {
@@ -221,7 +220,7 @@ public List getData() {
     }
 
     public static ListAppender createAppender(final String name, final boolean newLine, final boolean raw,
-            final Layout layout, final Filter filter) {
+            final Layout layout, final Filter filter) {
         return new ListAppender(name, filter, layout, newLine, raw);
     }
 
@@ -235,7 +234,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui
         private String name;
         private boolean entryPerNewLine;
         private boolean raw;
-        private Layout layout;
+        private Layout layout;
         private Filter filter;
 
         public Builder setName(@Required @PluginAttribute final String name) {
@@ -253,7 +252,7 @@ public Builder setRaw(@PluginAttribute final boolean raw) {
             return this;
         }
 
-        public Builder setLayout(@PluginElement final Layout layout) {
+        public Builder setLayout(@PluginElement final Layout layout) {
             this.layout = layout;
             return this;
         }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
index ea5f36e4007..3d7f2bd4620 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
@@ -14,9 +14,10 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-
 package org.apache.logging.log4j.core.test.junit;
 
+import java.lang.reflect.Parameter;
+
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.AbstractManager;
@@ -28,8 +29,6 @@
 import org.junit.jupiter.api.extension.ParameterResolver;
 import org.junit.platform.commons.support.ReflectionSupport;
 
-import java.lang.reflect.Parameter;
-
 import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
 
 /**
@@ -46,9 +45,6 @@ public boolean supportsParameter(final ParameterContext parameterContext, final
     @Override
     public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException {
         final LoggerContext loggerContext = getLoggerContext(extensionContext);
-        if (loggerContext == null) {
-            throw new ParameterResolutionException("No LoggerContext defined");
-        }
         final Configuration configuration = loggerContext.getConfiguration();
         final Parameter parameter = parameterContext.getParameter();
         final String name = Keys.getName(parameter);
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
index 6e206591a38..c858490e9a3 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
@@ -14,19 +14,19 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-
 package org.apache.logging.log4j.core.test.junit;
 
+import java.lang.reflect.Parameter;
+
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.plugins.di.Keys;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.api.extension.ParameterResolver;
 
-import java.lang.reflect.Parameter;
-
 import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
 
 /**
@@ -45,16 +45,18 @@ public boolean supportsParameter(
     public Object resolveParameter(
             ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
         final LoggerContext loggerContext = getLoggerContext(extensionContext);
-        if (loggerContext == null) {
-            throw new ParameterResolutionException("No LoggerContext defined");
-        }
         final String name = Keys.getName(parameterContext.getParameter());
         if (name.isEmpty()) {
             throw new ParameterResolutionException("No named annotation present after checking earlier");
         }
-        final Appender appender = loggerContext.getConfiguration().getAppender(name);
+        final String contextName = loggerContext.getName();
+        final Configuration configuration = loggerContext.getConfiguration();
+        final String configName = configuration.getName();
+        final Appender appender = configuration.getAppender(name);
         if (appender == null) {
-            throw new ParameterResolutionException("No appender named " + name);
+            final String error = String.format("No appender found for name '%s' in config='%s' and context='%s'",
+                    name, configName, contextName);
+            throw new ParameterResolutionException(error);
         }
         return appender;
     }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
index 9b809fc4a61..7b4ffbe5301 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
@@ -35,9 +35,10 @@ public ConfigurationResolver() {
     public Configuration resolveParameter(
             ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
         final LoggerContext loggerContext = getLoggerContext(extensionContext);
-        if (loggerContext == null) {
-            throw new ParameterResolutionException("No LoggerContext defined");
+        final Configuration configuration = loggerContext.getConfiguration();
+        if (configuration == null) {
+            throw new ParameterResolutionException("No Configuration defined");
         }
-        return loggerContext.getConfiguration();
+        return configuration;
     }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
index 7848c778958..bdf0515c85a 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
@@ -16,33 +16,28 @@
  */
 package org.apache.logging.log4j.core.test.junit;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import java.util.function.Consumer;
+
 import org.apache.logging.log4j.core.selector.ContextSelector;
-import org.apache.logging.log4j.plugins.di.DI;
 import org.apache.logging.log4j.plugins.di.Injector;
-import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.platform.commons.support.AnnotationSupport;
 
-public class ContextSelectorCallback implements BeforeAllCallback, AfterAllCallback {
+class ContextSelectorCallback implements BeforeAllCallback {
     @Override
     public void beforeAll(final ExtensionContext context) throws Exception {
         AnnotationSupport.findAnnotation(context.getTestClass(), ContextSelectorType.class)
                 .map(ContextSelectorType::value)
                 .ifPresent(contextSelectorClass -> {
-                    final Injector injector = DI.createInjector();
-                    injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
-                    injector.init();
-                    final Log4jContextFactory factory = injector.getInstance(Log4jContextFactory.class);
-                    LogManager.setFactory(factory);
+                    final LoggingTestContext testContext = LoggingTestContext.configurer()
+                            .setBootstrap(true)
+                            .setContextName(context.getRequiredTestClass().getSimpleName())
+                            .build();
+                    final Consumer configurer = injector ->
+                            injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
+                    testContext.init(configurer);
+                    LoggerContextResolver.setTestContext(context, testContext);
                 });
     }
-
-    @Override
-    public void afterAll(final ExtensionContext context) throws Exception {
-        AnnotationSupport.findAnnotation(context.getTestClass(), ContextSelectorType.class)
-                .ifPresent(ignored -> LogManager.setFactory(null));
-    }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
index 53bd60172b7..81343578172 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
@@ -16,17 +16,9 @@
  */
 package org.apache.logging.log4j.core.test.junit;
 
-import java.net.URI;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
-import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.LoggerContextAccessor;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.plugins.di.DI;
 import org.apache.logging.log4j.plugins.di.Injector;
 import org.apache.logging.log4j.test.junit.TypeBasedParameterResolver;
 import org.junit.jupiter.api.extension.AfterEachCallback;
@@ -34,17 +26,13 @@
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
-import org.junit.jupiter.api.extension.ExtensionContext.Store;
 import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.platform.commons.support.AnnotationSupport;
 
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
 class LoggerContextResolver extends TypeBasedParameterResolver implements BeforeAllCallback,
         BeforeEachCallback, AfterEachCallback {
-    private static final String FQCN = LoggerContextResolver.class.getName();
-    private static final Namespace BASE_NAMESPACE = Namespace.create(LoggerContext.class);
+    private static final Namespace NAMESPACE = Namespace.create(LoggingTestContext.class);
 
     public LoggerContextResolver() {
         super(LoggerContext.class);
@@ -54,30 +42,20 @@ public LoggerContextResolver() {
     public void beforeAll(ExtensionContext context) throws Exception {
         final Class testClass = context.getRequiredTestClass();
         AnnotationSupport.findAnnotation(testClass, LoggerContextSource.class)
-                .ifPresent(testSource -> setUpLoggerContext(testSource, context));
+                .ifPresent(testSource -> initializeTestContext(testSource, context));
     }
 
     @Override
     public void beforeEach(ExtensionContext context) throws Exception {
-        final Class testClass = context.getRequiredTestClass();
-        if (AnnotationSupport.isAnnotated(testClass, LoggerContextSource.class)) {
-            final Store testClassStore = context.getStore(BASE_NAMESPACE.append(testClass));
-            final LoggerContextAccessor accessor = testClassStore.get(LoggerContextAccessor.class, LoggerContextAccessor.class);
-            if (accessor == null) {
-                throw new IllegalStateException(
-                        "Specified @LoggerContextSource but no LoggerContext found for test class " +
-                                testClass.getCanonicalName());
-            }
-            if (testClassStore.get(ReconfigurationPolicy.class, ReconfigurationPolicy.class) == ReconfigurationPolicy.BEFORE_EACH) {
-                accessor.getLoggerContext().reconfigure();
-            }
+        if (AnnotationSupport.isAnnotated(context.getRequiredTestClass(), LoggerContextSource.class)) {
+            final LoggingTestContext testContext = getTestContext(context);
+            testContext.beforeEachTest();
         }
         AnnotationSupport.findAnnotation(context.getRequiredTestMethod(), LoggerContextSource.class)
                 .ifPresent(source -> {
-                    final LoggerContext loggerContext = setUpLoggerContext(source, context);
-                    if (source.reconfigure() == ReconfigurationPolicy.BEFORE_EACH) {
-                        loggerContext.reconfigure();
-                    }
+                    initializeTestContext(source, context);
+                    final LoggingTestContext testContext = getTestContext(context);
+                    testContext.beforeEachTest();
                 });
     }
 
@@ -85,10 +63,8 @@ public void beforeEach(ExtensionContext context) throws Exception {
     public void afterEach(ExtensionContext context) throws Exception {
         final Class testClass = context.getRequiredTestClass();
         if (AnnotationSupport.isAnnotated(testClass, LoggerContextSource.class)) {
-            final Store testClassStore = getTestStore(context);
-            if (testClassStore.get(ReconfigurationPolicy.class, ReconfigurationPolicy.class) == ReconfigurationPolicy.AFTER_EACH) {
-                testClassStore.get(LoggerContextAccessor.class, LoggerContextAccessor.class).getLoggerContext().reconfigure();
-            }
+            final LoggingTestContext testContext = getTestContext(context);
+            testContext.afterEachTest();
         }
     }
 
@@ -98,72 +74,42 @@ public LoggerContext resolveParameter(
         return getLoggerContext(extensionContext);
     }
 
-    static LoggerContext getLoggerContext(ExtensionContext context) {
-        final Store store = getTestStore(context);
-        final LoggerContextAccessor accessor = store.get(LoggerContextAccessor.class, LoggerContextAccessor.class);
-        assertNotNull(accessor);
-        return accessor.getLoggerContext();
+    private static void initializeTestContext(final LoggerContextSource source, final ExtensionContext extensionContext) {
+        final LoggingTestContext context = LoggingTestContext.configurer()
+                .setBootstrap(source.bootstrap())
+                .setConfigurationLocation(source.value())
+                .setContextName(source.name())
+                .setReconfigurationPolicy(source.reconfigure())
+                .setTimeout(source.timeout(), source.unit())
+                .setV1Config(source.v1config())
+                .setClassLoader(extensionContext.getRequiredTestClass().getClassLoader())
+                .build();
+        final Consumer configurer = extensionContext.getTestInstance()
+                .map(instance -> (Consumer) injector -> injector.registerBundle(instance))
+                .orElse(null);
+        context.init(configurer);
+        setTestContext(extensionContext, context);
     }
 
-    private static Store getTestStore(final ExtensionContext context) {
-        return context.getStore(BASE_NAMESPACE.append(context.getRequiredTestClass()));
+    static void setTestContext(final ExtensionContext context, final LoggingTestContext testContext) {
+        context.getStore(NAMESPACE).put(LoggingTestContext.class, testContext);
     }
 
-    private static LoggerContext setUpLoggerContext(final LoggerContextSource source, final ExtensionContext extensionContext) {
-        final String displayName = extensionContext.getDisplayName();
-        final Injector injector = extensionContext.getTestInstance().map(DI::createInjector).orElseGet(DI::createInjector);
-        injector.init();
-        final Log4jContextFactory loggerContextFactory;
-        if (source.bootstrap()) {
-            loggerContextFactory = new Log4jContextFactory(injector);
-            LogManager.setFactory(loggerContextFactory);
-        } else {
-            loggerContextFactory = (Log4jContextFactory) LogManager.getFactory();
-        }
-        final Class testClass = extensionContext.getRequiredTestClass();
-        final ClassLoader classLoader = testClass.getClassLoader();
-        final Map.Entry injectorContext = Map.entry(Injector.class.getName(), injector);
-        final String configLocation = source.value();
-        final URI configUri;
-        if (source.v1config()) {
-            System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, configLocation);
-            configUri = null; // handled by system property
-        } else {
-            configUri = configLocation.isEmpty() ? null : NetUtils.toURI(configLocation);
+    static LoggingTestContext getTestContext(final ExtensionContext context) {
+        final LoggingTestContext testContext = context.getStore(NAMESPACE).get(LoggingTestContext.class, LoggingTestContext.class);
+        if (testContext == null) {
+            throw new ParameterResolutionException("No LoggingTestContext defined");
         }
-        final LoggerContext context = loggerContextFactory.getContext(FQCN, classLoader, injectorContext, false, configUri, displayName);
-        assertNotNull(context, () -> "No LoggerContext created for " + testClass + " and config file " + configLocation);
-        final Store store = getTestStore(extensionContext);
-        store.put(ReconfigurationPolicy.class, source.reconfigure());
-        store.put(LoggerContextAccessor.class, new ContextHolder(context, source.timeout(), source.unit()));
-        return context;
+        return testContext;
     }
 
-    private static class ContextHolder implements Store.CloseableResource, LoggerContextAccessor {
-        private final LoggerContext context;
-        private final long shutdownTimeout;
-        private final TimeUnit unit;
-
-        private ContextHolder(final LoggerContext context, final long shutdownTimeout, final TimeUnit unit) {
-            this.context = context;
-            this.shutdownTimeout = shutdownTimeout;
-            this.unit = unit;
-        }
-
-        @Override
-        public LoggerContext getLoggerContext() {
-            return context;
-        }
-
-        @Override
-        public void close() throws Throwable {
-            try {
-                context.stop(shutdownTimeout, unit);
-            } finally {
-                System.clearProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL);
-                System.clearProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY);
-            }
+    static LoggerContext getLoggerContext(ExtensionContext context) {
+        final LoggingTestContext testContext = getTestContext(context);
+        final LoggerContext loggerContext = testContext.getLoggerContext();
+        if (loggerContext == null) {
+            throw new ParameterResolutionException("No LoggerContext defined");
         }
+        return loggerContext;
     }
 
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
index 118f71b2450..616a5d839f2 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
@@ -17,30 +17,28 @@
 package org.apache.logging.log4j.core.test.junit;
 
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.AbstractLifeCycle;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.LoggerContextAccessor;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
 import org.apache.logging.log4j.core.selector.ContextSelector;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.plugins.di.DI;
 import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.di.Keys;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.test.junit.CleanFiles;
 import org.apache.logging.log4j.test.junit.CleanFolders;
-import org.apache.logging.log4j.util.Strings;
+import org.apache.logging.log4j.util.Cast;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
+import org.opentest4j.AssertionFailedError;
 
 import static org.junit.Assert.assertNotNull;
 
@@ -59,14 +57,11 @@ public static LoggerContextRule createShutdownTimeoutLoggerContextRule(final Str
         return new LoggerContextRule(config, 10, TimeUnit.SECONDS);
     }
 
-    private static final String SYS_PROP_KEY_CLASS_NAME = "org.apache.logging.log4j.junit.LoggerContextRule#ClassName";
-    private static final String SYS_PROP_KEY_DISPLAY_NAME = "org.apache.logging.log4j.junit.LoggerContextRule#DisplayName";
+    private final LoggingTestContext.Configurer configurer;
     private final String configurationLocation;
     private LoggerContext loggerContext;
     private Class contextSelectorClass;
     private String testClassName;
-    private final long shutdownTimeout;
-    private final TimeUnit shutdownTimeUnit;
 
     /**
      * Constructs a new LoggerContextRule without a configuration file.
@@ -100,10 +95,13 @@ public LoggerContextRule(final String configurationLocation, final Class contextSelectorClass,
             final long shutdownTimeout, final TimeUnit shutdownTimeUnit) {
+        configurer = LoggingTestContext.configurer()
+                .setConfigurationLocation(configurationLocation)
+                .setTimeout(shutdownTimeout, shutdownTimeUnit)
+                // TODO(ms): can support ReconfigurationPolicy if we allow reuse of the context like in LoggerContextResolver
+                .setBootstrap(true);
         this.configurationLocation = configurationLocation;
         this.contextSelectorClass = contextSelectorClass;
-        this.shutdownTimeout = shutdownTimeout;
-        this.shutdownTimeUnit = shutdownTimeUnit;
     }
 
     public LoggerContextRule(final String configurationLocation, final int shutdownTimeout, final TimeUnit shutdownTimeUnit) {
@@ -116,45 +114,29 @@ public Statement apply(final Statement base, final Description description) {
         if (System.getProperties().containsKey("EBUG")) {
             StatusLogger.getLogger().setLevel(Level.DEBUG);
         }
+        final LoggingTestContext testContext = configurer.setClassLoader(description.getTestClass().getClassLoader())
+                .setContextName(Keys.getSpecifiedName(description.getAnnotations()).orElse(description.getMethodName()))
+                .build();
         testClassName = description.getClassName();
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                System.setProperty(SYS_PROP_KEY_CLASS_NAME, description.getClassName());
-                final String displayName = description.getDisplayName();
-                System.setProperty(SYS_PROP_KEY_DISPLAY_NAME, displayName);
-                final Injector injector = DI.createInjector();
+                final Consumer injectorConsumer;
                 if (contextSelectorClass != null) {
-                    injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
-                }
-                injector.init();
-                final Log4jContextFactory factory = new Log4jContextFactory(injector);
-                LogManager.setFactory(factory);
-                final String fqcn = getClass().getName();
-                final ClassLoader classLoader = description.getTestClass().getClassLoader();
-
-                if (Strings.isBlank(configurationLocation)) {
-                    loggerContext = factory.getContext(fqcn, classLoader, null, false);
-                } else if (configurationLocation.contains(",")) {
-                    loggerContext = factory.getContext(fqcn, classLoader, null, false, NetUtils.toURIs(configurationLocation),
-                            displayName);
+                    injectorConsumer = injector -> injector
+                            .registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
                 } else {
-                    loggerContext = factory.getContext(fqcn, classLoader, null, false, NetUtils.toURI(configurationLocation),
-                            displayName);
+                    injectorConsumer = null;
                 }
-                assertNotNull("Error initializing LoggerContext", loggerContext);
+                testContext.init(injectorConsumer);
+                loggerContext = testContext.getLoggerContext();
                 try {
                     base.evaluate();
                 } finally {
-                    if (!Configurator.shutdown(loggerContext, shutdownTimeout, shutdownTimeUnit)) {
-                        StatusLogger.getLogger().error("Logger context {} did not shutdown completely after {} {}.",
-                                loggerContext.getName(), shutdownTimeout, shutdownTimeUnit);
-                    }
+                    testContext.close();
                     loggerContext = null;
                     contextSelectorClass = null;
                     StatusLogger.getLogger().reset();
-                    System.clearProperty(SYS_PROP_KEY_CLASS_NAME);
-                    System.clearProperty(SYS_PROP_KEY_DISPLAY_NAME);
                 }
             }
         };
@@ -168,9 +150,8 @@ public void evaluate() throws Throwable {
      *            the name of the Appender to look up.
      * @return the named Appender or {@code null} if it wasn't defined in the configuration.
      */
-    @SuppressWarnings("unchecked") // Assume the call site knows what it is doing.
      public  T getAppender(final String name) {
-         return (T) getConfiguration().getAppenders().get(name);
+         return Cast.cast(getConfiguration().getAppenders().get(name));
      }
 
     /**
@@ -230,7 +211,7 @@ public ListAppender getListAppender(final String name) {
         if (appender instanceof ListAppender) {
             return (ListAppender) appender;
         }
-        throw new AssertionError("No ListAppender named " + name + " found.");
+        throw new AssertionFailedError("No ListAppender named " + name + " found.");
     }
 
     /**
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
index ccdc5027642..0747560d3ea 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
@@ -14,17 +14,8 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-
 package org.apache.logging.log4j.core.test.junit;
 
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.extension.ExtendWith;
-
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Inherited;
@@ -33,6 +24,15 @@
 import java.lang.annotation.Target;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.extension.ExtendWith;
+
 /**
  * Specifies a configuration file to use for unit tests. This configuration file will be loaded once and used for all tests
  * executed in the annotated test class unless otherwise specified by {@link #reconfigure()}. When annotated on a test method,
@@ -63,6 +63,14 @@
 @ExtendWith(AppenderManagerResolver.class)
 @ExtendWith(LoggerResolver.class)
 public @interface LoggerContextSource {
+
+    /**
+     * Specifies the LoggerContext name to run under. If no name is given or is an empty string, then
+     * the simple test class name or test method name will be used depending on whether this annotation is applied
+     * to a test class or test method respectively.
+     */
+    String name() default "";
+
     /**
      * Specifies the name of the configuration file to use for the annotated test.
      */
@@ -89,7 +97,8 @@
     boolean v1config() default false;
 
     /**
-     * Determines whether to bootstrap a fresh LoggerContextFactory.
+     * Determines whether to bootstrap a fresh LoggerContextFactory. This may be useful when configuring
+     * classes used by {@link org.apache.logging.log4j.core.impl.Log4jContextFactory}.
      */
     boolean bootstrap() default false;
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
index 80f72a8b144..bc0b166af45 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
@@ -14,9 +14,10 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-
 package org.apache.logging.log4j.core.test.junit;
 
+import java.lang.reflect.Parameter;
+
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.plugins.di.Keys;
@@ -25,8 +26,6 @@
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.api.extension.ParameterResolver;
 
-import java.lang.reflect.Parameter;
-
 import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
 
 class LoggerResolver implements ParameterResolver {
@@ -40,9 +39,6 @@ public boolean supportsParameter(final ParameterContext parameterContext, final
     public Logger resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
             throws ParameterResolutionException {
         final LoggerContext loggerContext = getLoggerContext(extensionContext);
-        if (loggerContext == null) {
-            throw new ParameterResolutionException("No LoggerContext defined");
-        }
         final String loggerName;
         final Parameter parameter = parameterContext.getParameter();
         if (Keys.hasName(parameter)) {
@@ -50,6 +46,10 @@ public Logger resolveParameter(final ParameterContext parameterContext, final Ex
         } else {
             loggerName = extensionContext.getRequiredTestClass().getCanonicalName();
         }
-        return loggerContext.getLogger(loggerName);
+        final Logger logger = loggerContext.getLogger(loggerName);
+        if (logger == null) {
+            throw new ParameterResolutionException("No Logger defined; name=" + loggerName);
+        }
+        return logger;
     }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java
new file mode 100644
index 00000000000..b93297fce81
--- /dev/null
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.test.junit;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.LoggerContextAccessor;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import org.apache.logging.log4j.core.util.NetUtils;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.util.Builder;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.opentest4j.AssertionFailedError;
+
+public class LoggingTestContext implements ExtensionContext.Store.CloseableResource, LoggerContextAccessor {
+    public static Configurer configurer() {
+        return new Configurer();
+    }
+
+    private static final String FQCN = LoggingTestContext.class.getName();
+    private final long timeout;
+    private final TimeUnit unit;
+    private final String configurationLocation;
+    private final URI configUri;
+    private final String contextName;
+    private final ReconfigurationPolicy reconfigurationPolicy;
+    private final boolean v1Config;
+    private final boolean bootstrap;
+    private final ClassLoader classLoader;
+    private LoggerContext loggerContext;
+
+    LoggingTestContext(final Configurer configuration) {
+        timeout = configuration.getTimeout();
+        unit = configuration.getUnit();
+        configurationLocation = configuration.getConfigurationLocation();
+        configUri = configuration.getConfigUri();
+        contextName = configuration.getContextName();
+        reconfigurationPolicy = configuration.getReconfigurationPolicy();
+        v1Config = configuration.isV1Config();
+        bootstrap = configuration.isBootstrap();
+        classLoader = configuration.getClassLoader();
+    }
+
+    public void init(final Consumer configurer) {
+        final Log4jContextFactory factory;
+        if (bootstrap) {
+            final Injector injector = DI.createInjector();
+            injector.init();
+            if (configurer != null) {
+                configurer.accept(injector);
+            }
+            factory = injector.getInstance(Log4jContextFactory.class);
+            LogManager.setFactory(factory);
+        } else {
+            factory = (Log4jContextFactory) LogManager.getFactory();
+        }
+        if (v1Config) {
+            System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, configurationLocation);
+            loggerContext = factory.getContext(FQCN, classLoader, null, false);
+        } else if (configUri != null) {
+            loggerContext = factory.getContext(FQCN, classLoader, false, configUri, contextName, configurer);
+        } else if (Strings.isBlank(configurationLocation)) {
+            loggerContext = factory.getContext(FQCN, classLoader, false, null, contextName, configurer);
+        } else if (configurationLocation.contains(",")) {
+            loggerContext = factory.getContext(FQCN, classLoader, null, false, NetUtils.toURIs(configurationLocation), contextName);
+        } else {
+            loggerContext = factory.getContext(FQCN, classLoader, false, NetUtils.toURI(configurationLocation), contextName, configurer);
+        }
+        if (loggerContext == null) {
+            throw new AssertionFailedError("Error creating LoggerContext");
+        }
+    }
+
+    public void beforeEachTest() {
+        if (reconfigurationPolicy == ReconfigurationPolicy.BEFORE_EACH) {
+            loggerContext.reconfigure();
+        }
+    }
+
+    public void afterEachTest() {
+        if (reconfigurationPolicy == ReconfigurationPolicy.AFTER_EACH) {
+            loggerContext.reconfigure();
+        }
+    }
+
+    @Override
+    public LoggerContext getLoggerContext() {
+        return loggerContext;
+    }
+
+    @Override
+    public void close() {
+        if (loggerContext != null) {
+            if (!loggerContext.stop(timeout, unit)) {
+                StatusLogger.getLogger().error("Logger context {} did not shutdown completely after {} {}.",
+                        contextName, timeout, unit);
+            }
+        }
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+
+    public String getConfigurationLocation() {
+        return configurationLocation;
+    }
+
+    public URI getConfigUri() {
+        return configUri;
+    }
+
+    public String getContextName() {
+        return contextName;
+    }
+
+    public ReconfigurationPolicy getReconfigurationPolicy() {
+        return reconfigurationPolicy;
+    }
+
+    public boolean isV1Config() {
+        return v1Config;
+    }
+
+    public boolean isBootstrap() {
+        return bootstrap;
+    }
+
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public static class Configurer implements Builder {
+        private long timeout;
+        private TimeUnit unit = TimeUnit.SECONDS;
+        private String configurationLocation;
+        private URI configUri;
+        private String contextName;
+        private ReconfigurationPolicy reconfigurationPolicy = ReconfigurationPolicy.NEVER;
+        private boolean v1Config;
+        private boolean bootstrap;
+        private ClassLoader classLoader;
+
+        public long getTimeout() {
+            return timeout;
+        }
+
+        public Configurer setTimeout(final long timeout, final TimeUnit unit) {
+            this.timeout = timeout;
+            this.unit = unit;
+            return this;
+        }
+
+        public TimeUnit getUnit() {
+            return unit;
+        }
+
+        public String getConfigurationLocation() {
+            return configurationLocation;
+        }
+
+        public Configurer setConfigurationLocation(final String configurationLocation) {
+            this.configurationLocation = configurationLocation;
+            return this;
+        }
+
+        public URI getConfigUri() {
+            return configUri;
+        }
+
+        public Configurer setConfigUri(final URI configUri) {
+            this.configUri = configUri;
+            return this;
+        }
+
+        public String getContextName() {
+            return contextName;
+        }
+
+        public Configurer setContextName(final String contextName) {
+            this.contextName = contextName;
+            return this;
+        }
+
+        public ReconfigurationPolicy getReconfigurationPolicy() {
+            return reconfigurationPolicy;
+        }
+
+        public Configurer setReconfigurationPolicy(final ReconfigurationPolicy reconfigurationPolicy) {
+            this.reconfigurationPolicy = reconfigurationPolicy;
+            return this;
+        }
+
+        public boolean isV1Config() {
+            return v1Config;
+        }
+
+        public Configurer setV1Config(final boolean v1Config) {
+            this.v1Config = v1Config;
+            return this;
+        }
+
+        public boolean isBootstrap() {
+            return bootstrap;
+        }
+
+        public Configurer setBootstrap(final boolean bootstrap) {
+            this.bootstrap = bootstrap;
+            return this;
+        }
+
+        public ClassLoader getClassLoader() {
+            return classLoader;
+        }
+
+        public Configurer setClassLoader(final ClassLoader classLoader) {
+            this.classLoader = classLoader;
+            return this;
+        }
+
+        @Override
+        public LoggingTestContext build() {
+            if (timeout != 0 && unit == null) {
+                throw new IllegalStateException("No unit specified for timeout value: " + timeout);
+            }
+            if (reconfigurationPolicy == null) {
+                reconfigurationPolicy = ReconfigurationPolicy.NEVER;
+            }
+            return new LoggingTestContext(this);
+        }
+    }
+}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
index f738e4c3568..e1623a3536b 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
@@ -16,27 +16,26 @@
  */
 package org.apache.logging.log4j.core.test.layout;
 
-import static org.junit.Assert.*;
-
 import java.io.IOException;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.impl.ContextDataFactory;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.ThrowableProxy;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
 
+import static org.junit.Assert.*;
+
 public class LogEventFixtures {
 
     /**
      * @return a log event that uses all the bells and whistles, features, nooks and crannies
      */
-    public static Log4jLogEvent createLogEvent() {
+    public static LogEvent createLogEvent() {
         final Marker cMarker = MarkerManager.getMarker("Marker1");
         final Marker pMarker1 = MarkerManager.getMarker("ParentMarker1");
         final Marker pMarker2 = MarkerManager.getMarker("ParentMarker2");
@@ -55,14 +54,15 @@ public static Log4jLogEvent createLogEvent() {
         ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 1"));
         ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 2"));
         final ThrowableProxy throwableProxy = new ThrowableProxy(ioException);
-        final StringMap contextData = ContextDataFactory.createContextData();
+        final StringMap contextData = new SortedArrayStringMap();
         contextData.putValue("MDC.A", "A_Value");
         contextData.putValue("MDC.B", "B_Value");
         final DefaultThreadContextStack contextStack = new DefaultThreadContextStack(true);
         contextStack.clear();
         contextStack.push("stack_msg1");
         contextStack.add("stack_msg2");
-        final Log4jLogEvent expected = Log4jLogEvent.newBuilder() //
+        // validate event?
+        return LogEvent.builder() //
                 .setLoggerName("a.B") //
                 .setMarker(cMarker) //
                 .setLoggerFqcn("f.q.c.n") //
@@ -74,15 +74,14 @@ public static Log4jLogEvent createLogEvent() {
                 .setContextStack(contextStack) //
                 .setThreadName("MyThreadName") //
                 .setSource(source) //
-                .setTimeMillis(1).build();
-        // validate event?
-        return expected;
+                .setTimeMillis(1)
+                .get();
     }
 
     public static void assertEqualLogEvents(final LogEvent expected, final LogEvent actual, final boolean includeSource,
             final boolean includeContext, final boolean includeStacktrace) {
         assertEquals(expected.getClass(), actual.getClass());
-        assertEquals(includeContext ? expected.getContextData() : ContextDataFactory.createContextData(), actual.getContextData());
+        assertEquals(includeContext ? expected.getContextData() : new SortedArrayStringMap(), actual.getContextData());
         assertEquals(expected.getContextStack(), actual.getContextStack());
         assertEquals(expected.getLevel(), actual.getLevel());
         assertEquals(expected.getLoggerName(), actual.getLoggerName());
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
index 76c1b64e12b..6742042c6be 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
@@ -16,13 +16,6 @@
  */
 package org.apache.logging.log4j.core;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.CoreLoggerContexts;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetSystemProperty;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -30,14 +23,22 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.impl.Log4jProperties;
+import org.apache.logging.log4j.core.test.CoreLoggerContexts;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetSystemProperty;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @Tag("functional")
-@SetSystemProperty(key = "log4j2.enable.direct.encoders", value = "true")
-@SetSystemProperty(key = "log4j2.configurationFile", value = "EventParameterMemoryLeakTest.xml")
+@SetSystemProperty(key = Log4jProperties.GC_ENABLE_DIRECT_ENCODERS, value = "true")
+@SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "EventParameterMemoryLeakTest.xml")
 public class EventParameterMemoryLeakTest {
 
     @Test
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
index f51f411bd56..a4b2fcb4452 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
@@ -16,11 +16,6 @@
  */
 package org.apache.logging.log4j.core;
 
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import java.io.File;
 import java.util.stream.Stream;
 
@@ -39,6 +34,8 @@
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 
+import static org.junit.jupiter.api.Assertions.*;
+
 @Tag("functional")
 public class LateConfigTest {
 
@@ -47,12 +44,13 @@ public class LateConfigTest {
     private static final String FQCN = Log4jContextFactory.class.getName();
 
     static Stream selectors() {
-        Injector injector = DI.createInjector();
-        injector.init();
-        return Stream
-                .of(new ClassLoaderContextSelector(injector.copy()), new BasicContextSelector(injector.copy()),
-                        new AsyncLoggerContextSelector(injector.copy()), new BasicAsyncLoggerContextSelector(injector.copy()))
-                .map(Log4jContextFactory::new);
+        return Stream.of(ClassLoaderContextSelector.class, BasicContextSelector.class, AsyncLoggerContextSelector.class, BasicAsyncLoggerContextSelector.class)
+                .map(contextSelectorClass -> {
+                    Injector inj = DI.createInjector();
+                    inj.registerBinding(ContextSelector.KEY, inj.getFactory(contextSelectorClass));
+                    inj.init();
+                    return inj.getInstance(Log4jContextFactory.class);
+                });
     }
 
     @ParameterizedTest
@@ -73,4 +71,3 @@ public void testReconfiguration(final Log4jContextFactory factory) throws Except
         assertSame(newConfig, sameConfig, "Configuration should not have been reset");
     }
 }
-
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
index bec9ab97437..8b2262ff3a0 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
@@ -16,21 +16,21 @@
  */
 package org.apache.logging.log4j.core;
 
+import java.util.List;
+
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.impl.ContextDataFactory;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.impl.LogEventFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
 import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.test.junit.Named;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.plugins.Factory;
+import org.apache.logging.log4j.plugins.Inject;
 import org.junit.jupiter.api.Test;
 
-import java.util.List;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
@@ -40,7 +40,7 @@
 public class LogEventFactoryTest {
 
     @Test
-    @LoggerContextSource(value = "log4j2-config.xml")
+    @LoggerContextSource(value = "log4j2-config.xml", bootstrap = true)
     public void testEvent(@Named("List") final ListAppender app, final LoggerContext context) {
         final org.apache.logging.log4j.Logger logger = context.getLogger("org.apache.test.LogEventFactory");
         logger.error("error message");
@@ -52,32 +52,36 @@ public void testEvent(@Named("List") final ListAppender app, final LoggerContext
     }
 
     public static class TestLogEventFactory implements LogEventFactory {
-        private final ContextDataInjector injector;
+        private final ContextDataInjector contextDataInjector;
+        private final ContextDataFactory contextDataFactory;
 
-        public TestLogEventFactory(final ContextDataInjector injector) {
-            this.injector = injector;
+        @Inject
+        public TestLogEventFactory(final ContextDataInjector contextDataInjector,
+                                   final ContextDataFactory contextDataFactory) {
+            this.contextDataInjector = contextDataInjector;
+            this.contextDataFactory = contextDataFactory;
         }
 
         @Override
         public LogEvent createEvent(final String loggerName, final Marker marker,
                                     final String fqcn, final Level level, final Message data,
                                     final List properties, final Throwable t) {
-            return Log4jLogEvent.newBuilder()
+            return LogEvent.builder()
                     .setLoggerName("Test")
                     .setMarker(marker)
                     .setLoggerFqcn(fqcn)
                     .setLevel(level)
                     .setMessage(data)
-                    .setContextDataInjector(injector)
-                    .setContextData(injector.injectContextData(properties, ContextDataFactory.createContextData()))
+                    .setContextDataInjector(contextDataInjector)
+                    .setContextDataFactory(contextDataFactory)
+                    .setContextData(properties)
                     .setThrown(t)
                     .build();
         }
     }
 
     @Factory
-    public LogEventFactory logEventFactory(final ContextDataInjector injector) {
-        return new TestLogEventFactory(injector);
+    public LogEventFactory logEventFactory(final TestLogEventFactory factory) {
+        return factory;
     }
 }
-
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
index 9561f37b584..2b8768bc772 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
@@ -16,18 +16,9 @@
  */
 package org.apache.logging.log4j.core;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
 import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LoggingException;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.util.FilteredObjectInputStream;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -41,112 +32,22 @@ public class LogEventTest {
     private static Message MESSAGE = new SimpleMessage("This is a test");
     private static TestClass TESTER = new TestClass();
 
-    @SuppressWarnings("BanSerializableRead")
-    @Test
-    public void testSerialization() throws Exception {
-        final LogEvent event1 = Log4jLogEvent.newBuilder() //
-                .setLoggerName(this.getClass().getName()) //
-                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
-                .setLevel(Level.INFO) //
-                .setMessage(new SimpleMessage("Hello, world!")) //
-                .build();
-        final Exception parent = new IllegalStateException("Test");
-        final Throwable child = new LoggingException("This is a test", parent);
-        final LogEvent event2 = Log4jLogEvent.newBuilder() //
-                .setLoggerName(this.getClass().getName()) //
-                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
-                .setLevel(Level.INFO) //
-                .setMessage(new SimpleMessage("Hello, world!")) //
-                .setThrown(child) //
-                .build();
-
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(event1);
-        oos.writeObject(event2);
-
-        final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-        final ObjectInputStream ois = new FilteredObjectInputStream(bais);
-        try {
-            ois.readObject();
-        } catch (final IOException ioe) {
-            fail("Exception processing event1");
-        }
-        try {
-            ois.readObject();
-        } catch (final IOException ioe) {
-            fail("Exception processing event2");
-        }
-    }
-
-    @SuppressWarnings("BanSerializableRead")
-    @Test
-    public void testNanoTimeIsNotSerialized1() throws Exception {
-        final LogEvent event1 = Log4jLogEvent.newBuilder() //
-                .setLoggerName(this.getClass().getName()) //
-                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
-                .setLevel(Level.INFO) //
-                .setMessage(new SimpleMessage("Hello, world!")) //
-                .setThreadName("this must be initialized or the test fails") //
-                .setNanoTime(12345678L) //
-                .build();
-        final LogEvent copy = new Log4jLogEvent.Builder(event1).build();
-
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(event1);
-
-        final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-        final ObjectInputStream ois = new FilteredObjectInputStream(bais);
-
-        final LogEvent actual = (LogEvent) ois.readObject();
-        assertNotEquals(copy, actual, "Different event: nanoTime");
-        assertNotEquals(copy.getNanoTime(), actual.getNanoTime(), "Different nanoTime");
-        assertEquals(0, actual.getNanoTime(), "deserialized nanoTime is zero");
-    }
-
-    @SuppressWarnings("BanSerializableRead")
-    @Test
-    public void testNanoTimeIsNotSerialized2() throws Exception {
-        final LogEvent event1 = Log4jLogEvent.newBuilder() //
-                .setLoggerName(this.getClass().getName()) //
-                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
-                .setLevel(Level.INFO) //
-                .setMessage(new SimpleMessage("Hello, world!")) //
-                .setThreadId(1) // this must be initialized or the test fails
-                .setThreadName("this must be initialized or the test fails") //
-                .setThreadPriority(2) // this must be initialized or the test fails
-                .setNanoTime(0) //
-                .build();
-        final LogEvent event2 = new Log4jLogEvent.Builder(event1).build();
-
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(event1);
-
-        final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-        final ObjectInputStream ois = new FilteredObjectInputStream(bais);
-
-        final LogEvent actual = (LogEvent) ois.readObject();
-        assertEquals(event2, actual, "both zero nanoTime");
-    }
-
     @Test
     @Disabled
     public void testEquals() {
-        final LogEvent event1 = Log4jLogEvent.newBuilder() //
+        final LogEvent event1 = LogEvent.builder() //
                 .setLoggerName(this.getClass().getName()) //
                 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
                 .setLevel(Level.INFO) //
                 .setMessage(new SimpleMessage("Hello, world!")) //
                 .build();
-        final LogEvent event2 = Log4jLogEvent.newBuilder() //
+        final LogEvent event2 = LogEvent.builder() //
                 .setLoggerName(this.getClass().getName()) //
                 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
                 .setLevel(Level.INFO) //
                 .setMessage(new SimpleMessage("Hello, world!")) //
                 .build();
-        final LogEvent event3 = Log4jLogEvent.newBuilder() //
+        final LogEvent event3 = LogEvent.builder() //
                 .setLoggerName(this.getClass().getName()) //
                 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
                 .setLevel(Level.INFO) //
@@ -167,9 +68,13 @@ private static class TestClass {
         private static final String FQCN = TestClass.class.getName();
 
         public StackTraceElement getEventSource(final String loggerName) {
-            final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName)
-                    .setLoggerFqcn(FQCN).setLevel(Level.INFO).setMessage(MESSAGE).build();
-            event.setIncludeLocation(true);
+            final LogEvent event = LogEvent.builder()
+                    .setLoggerName(loggerName)
+                    .setLoggerFqcn(FQCN)
+                    .setLevel(Level.INFO)
+                    .setMessage(MESSAGE)
+                    .includeLocation(true)
+                    .get();
             return event.getSource();
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
index b1944ed9c92..82bdd2a8c23 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
@@ -26,7 +26,7 @@ public class LoggerSerializationTest extends AbstractSerializationTest {
 
     @Parameters
     protected Stream data() {
-        return Stream.of(new LoggerContext("").getLogger("", null),
+        return Stream.of(LoggerContext.newBuilder().setName("").get().getLogger("", null),
                 LogManager.getRootLogger(),
                 LogManager.getLogger(),
                 LogManager.getLogger("test"));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThreadContextTestAccess.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThreadContextTestAccess.java
deleted file mode 100644
index fc35ae51b8d..00000000000
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThreadContextTestAccess.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core;
-
-import java.lang.reflect.Method;
-
-import org.apache.logging.log4j.ThreadContext;
-
-import static org.junit.jupiter.api.Assertions.fail;
-
-/**
- * 

- * Utility class to access package protected methods in {@code ThreadContext}. - *

- * - * @see ThreadContext - * @since 2.7 - */ -public final class ThreadContextTestAccess { - private ThreadContextTestAccess() { // prevent instantiation - } - - public static void init() { - try { - Class clazz = ThreadContext.class; - Method method = clazz.getDeclaredMethod("init"); - method.setAccessible(true); - method.invoke(null); - } catch (Exception ex) { - fail("Unable to reinitialize ThreadContext"); - } - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyRendererTest.java similarity index 96% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyRendererTest.java index 62725dab908..71695159826 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyRendererTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.impl; +package org.apache.logging.log4j.core; import java.util.ArrayList; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyTest.java new file mode 100644 index 00000000000..bcae2afb1bf --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/ThrowableProxyTest.java @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core; + +import java.io.IOException; +import java.net.BindException; +import java.net.InetSocketAddress; +import java.nio.channels.ServerSocketChannel; +import java.security.Permission; +import java.security.SecureRandom; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.IvParameterSpec; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.pattern.PlainTextRenderer; +import org.apache.logging.log4j.util.Strings; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * + */ +public class ThrowableProxyTest { + + public static class AlwaysThrowsError { + static { + if (true) { + throw new Error("I always throw an Error when initialized"); + } + } + } + + private boolean allLinesContain(final String text, final String containedText) { + final String[] lines = text.split("\n"); + for (final String line : lines) { + if (line.isEmpty()) { + continue; + } + if (!line.contains(containedText)) { + return false; + } + } + return true; + } + + private boolean lastLineContains(final String text, final String containedText) { + final String[] lines = text.split("\n"); + final String lastLine = lines[lines.length-1]; + return lastLine.contains(containedText); + } + + /** + * Attempts to instantiate a class that cannot initialize and then logs the stack trace of the Error. The logger + * must not fail when using {@link ThrowableProxy} to inspect the frames of the stack trace. + */ + @Test + public void testLogStackTraceWithClassThatCannotInitialize() { + final Error e = assertThrows(Error.class, AlwaysThrowsError::new); + // Print the stack trace to System.out for informational purposes + // System.err.println("### Here's the stack trace that we'll log with log4j ###"); + // e.printStackTrace(); + // System.err.println("### End stack trace ###"); + + final Logger logger = LogManager.getLogger(getClass()); + + assertDoesNotThrow(() -> { + // This is the critical portion of the test. The log message must be printed without + // throwing a java.lang.Error when introspecting the AlwaysThrowError class in the + // stack trace. + logger.error(e.getMessage(), e); + logger.error(e); + }); + } + + @Test + @DisabledForJreRange(min = JRE.JAVA_18) // custom SecurityManager instances throw UnsupportedOperationException + public void testLogStackTraceWithClassThatWillCauseSecurityException() throws IOException { + final SecurityManager sm = System.getSecurityManager(); + try { + System.setSecurityManager( + new SecurityManager() { + @Override + public void checkPermission(final Permission perm) { + if (perm instanceof RuntimePermission) { + // deny access to the class to trigger the security exception + if ("accessClassInPackage.sun.nio.ch".equals(perm.getName())) { + throw new SecurityException(perm.toString()); + } + } + } + }); + final BindException e = assertThrows(BindException.class, () -> { + ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); + ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); + }); + assertDoesNotThrow(() -> new ThrowableProxy(e)); + } finally { + // restore the security manager + System.setSecurityManager(sm); + } + } + + @Test + @DisabledForJreRange(min = JRE.JAVA_18) // custom SecurityManager instances throw UnsupportedOperationException + public void testLogStackTraceWithClassLoaderThatWithCauseSecurityException() throws Exception { + final SecurityManager sm = System.getSecurityManager(); + try { + System.setSecurityManager( + new SecurityManager() { + @Override + public void checkPermission(final Permission perm) { + if (perm instanceof RuntimePermission) { + // deny access to the classloader to trigger the security exception + if ("getClassLoader".equals(perm.getName())) { + throw new SecurityException(perm.toString()); + } + } + } + }); + final String algorithm = "AES/CBC/PKCS5Padding"; + final Cipher ec = Cipher.getInstance(algorithm); + final byte[] bytes = new byte[16]; // initialization vector + final SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(bytes); + final KeyGenerator generator = KeyGenerator.getInstance("AES"); + generator.init(128); + final IvParameterSpec algorithmParameterSpec = new IvParameterSpec(bytes); + ec.init(Cipher.ENCRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); + final byte[] raw = new byte[0]; + final byte[] encrypted = ec.doFinal(raw); + final Cipher dc = Cipher.getInstance(algorithm); + dc.init(Cipher.DECRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); + final BadPaddingException e = assertThrows(BadPaddingException.class, () -> dc.doFinal(encrypted)); + assertDoesNotThrow(() -> new ThrowableProxy(e)); + } finally { + // restore the existing security manager + System.setSecurityManager(sm); + } + } + + @Test + public void testSeparator_getExtendedStackTraceAsString() throws Exception { + final Throwable throwable = new IllegalArgumentException("This is a test"); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String separator = " | "; + final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString(null, + PlainTextRenderer.getInstance(), " | ", Strings.EMPTY); + assertTrue(allLinesContain(extendedStackTraceAsString, separator), extendedStackTraceAsString); + } + + @Test + public void testSuffix_getExtendedStackTraceAsString() throws Exception { + final Throwable throwable = new IllegalArgumentException("This is a test"); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString(suffix); + assertTrue(lastLineContains(extendedStackTraceAsString, suffix), extendedStackTraceAsString); + } + + @Test + public void testSuffix_getExtendedStackTraceAsStringWithCausedThrowable() throws Exception { + final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); + } + + @Test + public void testSuffix_getExtendedStackTraceAsStringWithSuppressedThrowable() throws Exception { + final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); + final Throwable throwable = new RuntimeException(cause); + throwable.addSuppressed(new IOException("This is a test")); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); + } + + @Test + public void testSuffix_getCauseStackTraceAsString() throws Exception { + final Throwable throwable = new IllegalArgumentException("This is a test"); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); + } + + @Test + public void testSuffix_getCauseStackTraceAsStringWithCausedThrowable() throws Exception { + final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); + } + + @Test + public void testSuffix_getCauseStackTraceAsStringWithSuppressedThrowable() throws Exception { + final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); + final Throwable throwable = new RuntimeException(cause); + throwable.addSuppressed(new IOException("This is a test")); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + + final String suffix = "some suffix"; + assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); + } + + @Test + public void testStack() { + final Map map = new HashMap<>(); + final Deque> stack = new ArrayDeque<>(); + final Throwable throwable = new IllegalStateException("This is a test"); + final ThrowableProxy proxy = new ThrowableProxy(throwable); + final ExtendedStackTraceElement[] callerPackageData = ThrowableProxyHelper.toExtendedStackTrace(proxy, stack, map, null, + throwable.getStackTrace()); + assertNotNull(callerPackageData, "No package data returned"); + } + + /** + * Tests LOG4J2-934. + */ + @Test + public void testCircularSuppressedExceptions() { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(); + e2.addSuppressed(e1); + e1.addSuppressed(e2); + LogManager.getLogger().error("Error", e1); + } + + @Test + public void testSuppressedExceptions() { + final Exception e = new Exception("Root exception"); + e.addSuppressed(new IOException("Suppressed #1")); + e.addSuppressed(new IOException("Suppressed #2")); + LogManager.getLogger().error("Error", e); + final ThrowableProxy proxy = new ThrowableProxy(e); + final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); + assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); + assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); + } + + @Test + public void testCauseSuppressedExceptions() { + final Exception cause = new Exception("Nested exception"); + cause.addSuppressed(new IOException("Suppressed #1")); + cause.addSuppressed(new IOException("Suppressed #2")); + LogManager.getLogger().error("Error", new Exception(cause)); + final ThrowableProxy proxy = new ThrowableProxy(new Exception("Root exception", cause)); + final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); + assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); + assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); + } + + /** + * Tests LOG4J2-934. + */ + @Test + public void testCircularSuppressedNestedException() { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(e1); + e2.addSuppressed(e1); + e1.addSuppressed(e2); + LogManager.getLogger().error("Error", e1); + } + + /** + * . + */ + @Test + public void testCircularCauseExceptions() { + final Exception e1 = new Exception(); + final Exception e2 = new Exception(e1); + e1.initCause(e2); + LogManager.getLogger().error("Error", e1); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java index 148d079427b..61d929a9fb9 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java @@ -16,11 +16,14 @@ */ package org.apache.logging.log4j.core.appender; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.ConsoleAppender.Target; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; @@ -31,9 +34,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -41,7 +41,7 @@ import static org.mockito.Mockito.atLeastOnce; @ExtendWith(MockitoExtension.class) -@SetSystemProperty(key = "log4j.skipJansi", value = "true") +@SetSystemProperty(key = Log4jProperties.JANSI_ENABLED, value = "false") public class ConsoleAppenderTest { ByteArrayOutputStream baos; @@ -80,12 +80,12 @@ private void testConsoleStreamManagerDoesNotClose(final PrintStream ps, final Ta app.start(); assertTrue(app.isStarted(), "Appender did not start"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("TestLogger") // .setLoggerFqcn(ConsoleAppenderTest.class.getName()) // .setLevel(Level.INFO) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); app.append(event); app.stop(); @@ -113,12 +113,12 @@ private void testFollowSystemPrintStream(final PrintStream ps, final Target targ assertEquals(target, app.getTarget()); app.start(); try { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("TestLogger") // .setLoggerFqcn(ConsoleAppenderTest.class.getName()) // .setLevel(Level.INFO) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); assertTrue(app.isStarted(), "Appender did not start"); systemSetter.systemSet(new PrintStream(baos)); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java index 7b07328b4ed..82279e4f7aa 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java @@ -16,12 +16,20 @@ */ package org.apache.logging.log4j.core.appender; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFileAttributes; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.stream.Stream; + import org.apache.commons.lang3.SystemUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.util.FileUtils; @@ -34,15 +42,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.stream.Stream; - import static org.apache.logging.log4j.util.Unbox.box; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assumptions.assumeTrue; @@ -90,10 +89,14 @@ public void testFilePermissionsAPI(final String filePermissions, final boolean c long prevLen = curLen; assertEquals(curLen, 0, "File length: " + curLen); for (int i = 0; i < 100; ++i) { - final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") // - .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()).setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) // - .setTimeMillis(System.currentTimeMillis()).build(); + final LogEvent event = LogEvent.builder() + .setLoggerName("TestLogger") + .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()) + .setLevel(Level.INFO) + .setMessage(new SimpleMessage("Test")) + .setThreadName(this.getClass().getSimpleName()) + .setTimeMillis(System.currentTimeMillis()) + .get(); try { appender.append(event); curLen = file.length(); @@ -147,10 +150,14 @@ public void testFileUserGroupAPI(final String filePermissions, final int fileInd long prevLen = curLen; assertEquals(curLen, 0, file + " File length: " + curLen); for (int i = 0; i < 100; ++i) { - final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") // - .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()).setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) // - .setTimeMillis(System.currentTimeMillis()).build(); + final LogEvent event = LogEvent.builder() + .setLoggerName("TestLogger") + .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()) + .setLevel(Level.INFO) + .setMessage(new SimpleMessage("Test")) + .setThreadName(this.getClass().getSimpleName()) + .setTimeMillis(System.currentTimeMillis()) + .get(); try { appender.append(event); curLen = file.length(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java index 28cd98f0bda..d6fbb439bee 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java @@ -16,21 +16,6 @@ */ package org.apache.logging.log4j.core.appender; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.util.Integers; -import org.apache.logging.log4j.core.util.Throwables; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.test.junit.CleanUpFiles; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -45,6 +30,20 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.util.Integers; +import org.apache.logging.log4j.core.util.Throwables; +import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.test.junit.CleanUpFiles; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + import static org.junit.jupiter.api.Assertions.*; /** @@ -129,14 +128,14 @@ public void testSmallestBufferSize(final boolean createOnDemand) throws Exceptio assertEquals(0, curLen, "File length: " + curLen); for (int i = 0; i < 100; ++i) { // @formatter:off - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("TestLogger") .setLoggerFqcn(FileAppenderTest.class.getName()) .setLevel(Level.INFO) .setMessage(new SimpleMessage("Test")) .setThreadName(this.getClass().getSimpleName()) .setTimeMillis(System.currentTimeMillis()) - .build(); + .get(); // @formatter:on appender.append(event); curLen = file.length(); @@ -257,14 +256,14 @@ private static void writer(final boolean locking, final int logEventCount, final } for (int i = 0; i < logEventCount; ++i) { // @formatter:off - final LogEvent logEvent = Log4jLogEvent.newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName("TestLogger") .setLoggerFqcn(FileAppenderTest.class.getName()) .setLevel(Level.INFO) .setMessage(new SimpleMessage("Test")) .setThreadName(name) .setTimeMillis(System.currentTimeMillis()) - .build(); + .get(); // @formatter:on appender.append(logEvent); Thread.sleep(25); // Give up control long enough for another thread/process to occasionally do something. diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java index 6695f51be9b..f4ac1ed62e2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -28,9 +30,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.util.concurrent.TimeUnit; - @Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) @Plugin("Hanging") public class HangingAppender extends AbstractAppender { @@ -63,7 +62,7 @@ public static HangingAppender createAppender( @PluginAttribute final long delay, @PluginAttribute final long startupDelay, @PluginAttribute final long shutdownDelay, - @PluginElement final Layout layout, + @PluginElement final Layout layout, @PluginElement final Filter filter) { return new HangingAppender(name, delay, startupDelay, shutdownDelay); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/InMemoryAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/InMemoryAppenderTest.java index cf386e37cfe..1a3846ca18a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/InMemoryAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/InMemoryAppenderTest.java @@ -19,10 +19,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.core.test.appender.InMemoryAppender; +import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; @@ -30,9 +31,11 @@ public class InMemoryAppenderTest { + private final Configuration configuration = new DefaultConfiguration(); + @Test public void testAppender() { - final Layout layout = PatternLayout.createDefaultLayout(); + final Layout layout = PatternLayout.createDefaultLayout(configuration); final boolean writeHeader = true; final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader, null); final String expectedHeader = null; @@ -41,7 +44,10 @@ public void testAppender() { @Test public void testHeaderRequested() { - final PatternLayout layout = PatternLayout.newBuilder().setHeader("HEADERHEADER").build(); + final PatternLayout layout = PatternLayout.newBuilder() + .setConfiguration(configuration) + .setHeader("HEADERHEADER") + .build(); final boolean writeHeader = true; final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader, null); final String expectedHeader = "HEADERHEADER"; @@ -50,7 +56,10 @@ public void testHeaderRequested() { @Test public void testHeaderSuppressed() { - final PatternLayout layout = PatternLayout.newBuilder().setHeader("HEADERHEADER").build(); + final PatternLayout layout = PatternLayout.newBuilder() + .setConfiguration(configuration) + .setHeader("HEADERHEADER") + .build(); final boolean writeHeader = false; final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader, null); final String expectedHeader = null; @@ -58,12 +67,12 @@ public void testHeaderSuppressed() { } private void assertMessage(final String string, final InMemoryAppender app, final String header) { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("TestLogger") // .setLoggerFqcn(InMemoryAppenderTest.class.getName()) // .setLevel(Level.INFO) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); app.start(); assertTrue(app.isStarted(), "Appender did not start"); app.append(event); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java index 5bd2c32c630..dbec2890604 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java @@ -53,7 +53,11 @@ private void addAppender(final OutputStream outputStream, final String outputStr final LoggerContext context = LoggerContext.getContext(false); final Configuration config = context.getConfiguration(); final PatternLayout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true); + final Appender appender = OutputStreamAppender.newBuilder() + .setName(outputStreamName) + .setTarget(outputStream) + .setLayout(layout) + .build(); appender.start(); config.addAppender(appender); ConfigurationTestUtils.updateLoggers(appender, config); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileManagerTest.java index 821727bf08a..6aa2e0b66ec 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileManagerTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileManagerTest.java @@ -22,11 +22,11 @@ import java.io.OutputStream; import java.io.RandomAccessFile; -import org.apache.logging.log4j.core.util.NullOutputStream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /** * Tests the RandomAccessFileManager class. @@ -44,7 +44,7 @@ public class RandomAccessFileManagerTest { public void testWrite_multiplesOfBufferSize() throws IOException { final File file = new File(tempDir, "testWrite_multiplesOfBufferSize.bin"); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); try (final RandomAccessFileManager manager = new RandomAccessFileManager( null, raf, file.getName(), os, RandomAccessFileManager.DEFAULT_BUFFER_SIZE, null, null, true)) { @@ -66,7 +66,7 @@ public void testWrite_multiplesOfBufferSize() throws IOException { public void testWrite_dataExceedingBufferSize() throws IOException { final File file = new File(tempDir, "testWrite_dataExceedingBufferSize.bin"); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final int size = RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3 + 1; try (final RandomAccessFileManager manager = new RandomAccessFileManager( null, raf, file.getName(), os, @@ -84,7 +84,7 @@ public void testWrite_dataExceedingBufferSize() throws IOException { public void testConfigurableBufferSize() throws IOException { final File file = new File(tempDir, "testConfigurableBufferSize.bin"); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final int bufferSize = 4 * 1024; assertNotEquals(bufferSize, RandomAccessFileManager.DEFAULT_BUFFER_SIZE); try (final RandomAccessFileManager manager = new RandomAccessFileManager( @@ -99,7 +99,7 @@ public void testConfigurableBufferSize() throws IOException { public void testWrite_dataExceedingMinBufferSize() throws IOException { final File file = new File(tempDir, "testWrite_dataExceedingMinBufferSize.bin"); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final int bufferSize = 1; final int size = bufferSize * 3 + 1; try (final RandomAccessFileManager manager = new RandomAccessFileManager( diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTestBase.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTestBase.java index 3ef20d3ded5..2c9c8e0fb34 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTestBase.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTestBase.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -154,7 +153,7 @@ protected Facility getExpectedFacility() { } protected void validate(final SyslogAppender syslogAppender) { - final Layout layout = syslogAppender.getLayout(); + final Layout layout = syslogAppender.getLayout(); if (layout instanceof SyslogLayout) { validate((SyslogLayout) layout); } else if (layout instanceof Rfc5424Layout) { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java index 756d21d9b2d..04de292f1f1 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java @@ -80,8 +80,14 @@ public void sendStructuredMessagesOverTls() throws IOException, InterruptedExcep } private void initServerSocketFactory() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), null, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .build(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc); serverSocketFactory = sslConfiguration.getSslServerSocketFactory(); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java index 392862e5355..36ef731bb83 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java @@ -77,7 +77,11 @@ private void addAppender(final Writer writer, final String writerName) { final LoggerContext context = LoggerContext.getContext(false); final Configuration config = context.getConfiguration(); final PatternLayout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true); + final Appender appender = WriterAppender.newBuilder() + .setName(writerName) + .setLayout(layout) + .setTarget(writer) + .build(); appender.start(); config.addAppender(appender); ConfigurationTestUtils.updateLoggers(appender, config); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java index dfb498eb09d..1baebe4798d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java @@ -16,24 +16,17 @@ */ package org.apache.logging.log4j.core.appender.db; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.io.Serializable; import org.apache.logging.log4j.core.LogEvent; import org.junit.Test; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.*; + public class AbstractDatabaseManagerTest { // this stub is provided because mocking constructors is hard private static class StubDatabaseManager extends AbstractDatabaseManager { @@ -63,7 +56,7 @@ protected void startupInternal() throws Exception { } @Override - protected void writeInternal(final LogEvent event, final Serializable serializable) { + protected void writeInternal(final LogEvent event, final Object serializable) { // noop } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java index 17c44622aa9..fc47e19e95a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java @@ -16,15 +16,6 @@ */ package org.apache.logging.log4j.core.appender.nosql; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; - import java.io.IOException; import java.util.Collection; import java.util.Date; @@ -37,10 +28,9 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AppenderLoggingException; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.test.junit.ThreadContextStackRule; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -53,6 +43,12 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; + @RunWith(MockitoJUnitRunner.class) public class NoSqlDatabaseManagerTest { @Mock @@ -136,7 +132,7 @@ public void testWriteInternal01() { manager.connectAndStart(); then(provider).should().getConnection(); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLevel(Level.WARN) .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal01") .setMessage(message) @@ -145,7 +141,7 @@ public void testWriteInternal01() { .setThreadName("MyThread-A") .setThreadPriority(1) .setTimeMillis(1234567890123L) - .build(); + .get(); manager.writeInternal(event, null); then(connection).should().insertObject(captor.capture()); @@ -204,7 +200,7 @@ public void testWriteInternal02() { final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack(); ThreadContext.clearStack(); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLevel(Level.DEBUG) .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal02") .setMessage(message) @@ -215,9 +211,9 @@ public void testWriteInternal02() { .setThreadPriority(1) .setTimeMillis(987654321564L) .setThrown(exception) - .setContextData(ContextDataFactory.createContextData(context)) + .setContextData(new SortedArrayStringMap(context)) .setContextStack(stack) - .build(); + .get(); manager.writeInternal(event, null); then(connection).should().insertObject(captor.capture()); @@ -303,7 +299,7 @@ public void testWriteInternal03() { final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack(); ThreadContext.clearStack(); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLevel(Level.DEBUG) .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal02") .setMessage(message) @@ -316,9 +312,9 @@ public void testWriteInternal03() { .setThreadPriority(1) .setTimeMillis(987654321564L) .setThrown(exception2) - .setContextData(ContextDataFactory.createContextData(context)) + .setContextData(new SortedArrayStringMap(context)) .setContextStack(stack) - .build(); + .get(); manager.writeInternal(event, null); then(connection).should().insertObject(captor.capture()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicyTest.java index b03d64b186c..3c87f892226 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicyTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicyTest.java @@ -18,7 +18,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; @@ -38,31 +37,51 @@ public void testUpdate() { new KeyValuePair("INFO", "DEBUG"), new KeyValuePair("WARN", "INFO") }; final String loggerNameRewrite = "com.foo.bar"; - LogEvent logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameRewrite) - .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.INFO) - .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none") - .setTimeMillis(1).build(); + LogEvent logEvent = LogEvent.builder() + .setLoggerName(loggerNameRewrite) + .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()") + .setLevel(Level.INFO) + .setMessage(new SimpleMessage("Test")) + .setThrown(new RuntimeException("test")) + .setThreadName("none") + .setTimeMillis(1) + .build(); final LoggerNameLevelRewritePolicy updatePolicy = LoggerNameLevelRewritePolicy.createPolicy(loggerNameRewrite, rewrite); LogEvent rewritten = updatePolicy.rewrite(logEvent); assertEquals(Level.DEBUG, rewritten.getLevel()); - logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameRewrite) - .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.WARN) - .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none") - .setTimeMillis(1).build(); + logEvent = LogEvent.builder() + .setLoggerName(loggerNameRewrite) + .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()") + .setLevel(Level.WARN) + .setMessage(new SimpleMessage("Test")) + .setThrown(new RuntimeException("test")) + .setThreadName("none") + .setTimeMillis(1) + .build(); rewritten = updatePolicy.rewrite(logEvent); assertEquals(Level.INFO, rewritten.getLevel()); final String loggerNameReadOnly = "com.nochange"; - logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameReadOnly) - .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.INFO) - .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none") - .setTimeMillis(1).build(); + logEvent = LogEvent.builder() + .setLoggerName(loggerNameReadOnly) + .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()") + .setLevel(Level.INFO) + .setMessage(new SimpleMessage("Test")) + .setThrown(new RuntimeException("test")) + .setThreadName("none") + .setTimeMillis(1) + .build(); rewritten = updatePolicy.rewrite(logEvent); assertEquals(Level.INFO, rewritten.getLevel()); - logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameReadOnly) - .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.WARN) - .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none") - .setTimeMillis(1).build(); + logEvent = LogEvent.builder() + .setLoggerName(loggerNameReadOnly) + .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()") + .setLevel(Level.WARN) + .setMessage(new SimpleMessage("Test")) + .setThrown(new RuntimeException("test")) + .setThreadName("none") + .setTimeMillis(1) + .build(); rewritten = updatePolicy.rewrite(logEvent); assertEquals(Level.WARN, rewritten.getLevel()); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java index 74058da1bba..4d27fd5a464 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicyTest.java @@ -1,49 +1,46 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache license, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the license for the specific language governing permissions and -* limitations under the license. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ package org.apache.logging.log4j.core.appender.rewrite; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; import org.apache.logging.log4j.spi.MutableThreadContextStack; import org.apache.logging.log4j.spi.ThreadContextStack; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - import static org.apache.logging.log4j.core.test.hamcrest.MapMatchers.hasSize; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - +import static org.junit.jupiter.api.Assertions.*; public class MapRewritePolicyTest { - private static final StringMap stringMap = ContextDataFactory.createContextData(); + private static final StringMap stringMap = new SortedArrayStringMap(); private static Map map = new HashMap<>(); private static KeyValuePair[] rewrite; private static LogEvent logEvent0, logEvent1, logEvent2, logEvent3; @@ -53,7 +50,7 @@ public static void setupClass() { stringMap.putValue("test1", "one"); stringMap.putValue("test2", "two"); map = stringMap.toMap(); - logEvent0 = Log4jLogEvent.newBuilder() // + logEvent0 = LogEvent.builder() // .setLoggerName("test") // .setContextData(stringMap) // .setLoggerFqcn("MapRewritePolicyTest.setupClass()") // @@ -62,15 +59,16 @@ public static void setupClass() { .setThrown(new RuntimeException("test")) // .setThreadName("none") .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 28)) - .setTimeMillis(2).build(); + .setTimeMillis(2) + .build(); - logEvent1 = ((Log4jLogEvent) logEvent0).asBuilder() // + logEvent1 = LogEvent.builderFrom(logEvent0) .setMessage(new StringMapMessage(map)) // .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 29)) // .build(); final ThreadContextStack stack = new MutableThreadContextStack(new ArrayList<>(map.values())); - logEvent2 = ((Log4jLogEvent) logEvent0).asBuilder() // + logEvent2 = LogEvent.builderFrom(logEvent0) .setContextStack(stack) // .setMarker(MarkerManager.getMarker("test")) // .setLevel(Level.TRACE) // @@ -78,7 +76,7 @@ public static void setupClass() { .setTimeMillis(20000000) // .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 30)) // .build(); - logEvent3 = ((Log4jLogEvent) logEvent0).asBuilder() // + logEvent3 = LogEvent.builderFrom(logEvent0) .setContextStack(stack) // .setLevel(Level.ALL) // .setMessage(new StringMapMessage(map)) // @@ -91,6 +89,7 @@ public static void setupClass() { @Test public void addTest() { final MapRewritePolicy addPolicy = MapRewritePolicy.createPolicy("Add", rewrite); + assertNotNull(addPolicy); LogEvent rewritten = addPolicy.rewrite(logEvent0); compareLogEvents(logEvent0, rewritten); assertEquals(logEvent0.getMessage(), rewritten.getMessage(), "Simple log message changed"); @@ -111,6 +110,7 @@ public void addTest() { @Test public void updateTest() { final MapRewritePolicy updatePolicy = MapRewritePolicy.createPolicy("Update", rewrite); + assertNotNull(updatePolicy); LogEvent rewritten = updatePolicy.rewrite(logEvent0); compareLogEvents(logEvent0, rewritten); assertEquals(logEvent0.getMessage(), rewritten.getMessage(), "Simple log message changed"); @@ -131,6 +131,7 @@ public void updateTest() { @Test public void defaultIsAdd() { final MapRewritePolicy addPolicy = MapRewritePolicy.createPolicy(null, rewrite); + assertNotNull(addPolicy); LogEvent rewritten = addPolicy.rewrite(logEvent0); compareLogEvents(logEvent0, rewritten); assertEquals(logEvent0.getMessage(), rewritten.getMessage(), "Simple log message changed"); @@ -161,7 +162,6 @@ private void checkUpdated(final Map updatedMap) { assertThat("wrong size", updatedMap, hasSize(2)); } - @SuppressWarnings("deprecation") private void compareLogEvents(final LogEvent orig, final LogEvent changed) { // Ensure that everything but the Mapped Data is still the same assertEquals(orig.getLoggerName(), changed.getLoggerName(), "LoggerName changed"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/TestRewritePolicy.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/TestRewritePolicy.java index 508ff34e568..0a8cc235149 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/TestRewritePolicy.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rewrite/TestRewritePolicy.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.appender.rewrite; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginFactory; @@ -31,7 +30,7 @@ public class TestRewritePolicy implements RewritePolicy { @Override public LogEvent rewrite(final LogEvent source) { - return new Log4jLogEvent.Builder(source).build(); + return source.copy(); } @PluginFactory diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicyTest.java index f4e995a1f2a..d76b420c0d3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicyTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicyTest.java @@ -14,14 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.rolling; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.RollingFileAppender; import org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender; +import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.NullConfiguration; +import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.layout.PatternLayout; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,7 +33,7 @@ public class CronTriggeringPolicyTest { private static final String CRON_EXPRESSION = "0 0 0 * * ?"; - private NullConfiguration configuration; + private Configuration configuration; // TODO Need a CleanRegexFiles("testcmd.\\.log\\..*"); // @Rule @@ -41,7 +41,7 @@ public class CronTriggeringPolicyTest { @BeforeEach public void before() { - configuration = new NullConfiguration(); + configuration = new DefaultConfiguration(); } private CronTriggeringPolicy createPolicy() { @@ -124,7 +124,7 @@ private void testFactoryMethod() { try (RollingFileManager fileManager = RollingFileManager.getFileManager("target/testcmd3.log", "target/testcmd3.log.%d{yyyy-MM-dd}", true, true, triggerPolicy, rolloverStrategy, null, - PatternLayout.createDefaultLayout(), 0, true, false, null, null, null, configuration)) { + PatternLayout.createDefaultLayout(configuration), 0, true, false, null, null, null, configuration)) { assertNotNull(fileManager); // trigger rollover fileManager.initialize(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java index 4f36297258d..03847958d2d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java @@ -16,13 +16,6 @@ */ package org.apache.logging.log4j.core.appender.rolling; -import org.apache.commons.lang3.RandomStringUtils; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.apache.logging.log4j.plugins.Named; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - import java.io.File; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -31,11 +24,20 @@ import java.nio.file.StandardCopyOption; import java.util.concurrent.CountDownLatch; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.plugins.Named; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + import static org.assertj.core.api.Assertions.assertThat; /** * Validate rolling with a file pattern that contains leading zeros for the increment. */ +@Timeout(30) public class RollingAppenderCountTest extends AbstractRollingListenerTest { private static final String SOURCE = "src/test/resources/__files"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java index ff95f16f426..b625013acf0 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java @@ -16,16 +16,17 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.File; +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; - -import java.io.File; -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -34,51 +35,52 @@ /** * LOG4J2-1804. */ +@Timeout(30) public class RollingAppenderCronAndSizeTest extends AbstractRollingListenerTest { private static final String CONFIG = "log4j-rolling-cron-and-size.xml"; private static final String DIR = "target/rolling-cron-size"; - // we'll probably roll over more than 30 times, but that's a sufficient amount of test data - private final CountDownLatch rollover = new CountDownLatch(30); + // we'll probably roll over more than 30 times, but that's a sufficient amount of test data + private final CountDownLatch rollover = new CountDownLatch(30); - @Test - @CleanUpDirectories(DIR) - @LoggerContextSource(value = CONFIG, timeout = 10) - public void testAppender(final Logger logger, @Named("RollingFile") final RollingFileManager manager) throws Exception { - manager.addRolloverListener(this); - Random rand = new Random(currentTimeMillis.get()); - for (int j=0; j < 100; ++j) { - int count = rand.nextInt(100); - for (int i = 0; i < count; ++i) { - logger.debug("This is test message number {}", i); - } - currentTimeMillis.addAndGet(rand.nextInt(50)); - } + @Test + @CleanUpDirectories(DIR) + @LoggerContextSource(value = CONFIG, timeout = 10) + public void testAppender(final Logger logger, @Named("RollingFile") final RollingFileManager manager) throws Exception { + manager.addRolloverListener(this); + Random rand = new Random(currentTimeMillis.get()); + for (int j=0; j < 100; ++j) { + int count = rand.nextInt(100); + for (int i = 0; i < count; ++i) { + logger.debug("This is test message number {}", i); + } + currentTimeMillis.addAndGet(rand.nextInt(50)); + } - rollover.await(); + rollover.await(); - final File dir = new File(DIR); - assertThat(dir).isNotEmptyDirectory(); - assertThat(dir).isDirectoryContaining("glob:**.log"); - final File[] files = dir.listFiles(); - assertNotNull(files); - Arrays.sort(files); - int fileCounter = 0; - String previous = ""; - for (final File file: files) { - final String actual = file.getName(); - final String[] fileParts = actual.split("[_.]"); - fileCounter = previous.equals(fileParts[1]) ? ++fileCounter : 1; - previous = fileParts[1]; - assertEquals(Integer.toString(fileCounter), fileParts[2], - "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual); - } + final File dir = new File(DIR); + assertThat(dir).isNotEmptyDirectory(); + assertThat(dir).isDirectoryContaining("glob:**.log"); + final File[] files = dir.listFiles(); + assertNotNull(files); + Arrays.sort(files); + int fileCounter = 0; + String previous = ""; + for (final File file: files) { + final String actual = file.getName(); + final String[] fileParts = actual.split("[_.]"); + fileCounter = previous.equals(fileParts[1]) ? ++fileCounter : 1; + previous = fileParts[1]; + assertEquals(Integer.toString(fileCounter), fileParts[2], + "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual); + } - } + } - @Override - public void rolloverComplete(final String fileName) { - rollover.countDown(); - } + @Override + public void rolloverComplete(final String fileName) { + rollover.countDown(); + } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java index c3f694dddda..ae9e0033532 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java @@ -16,21 +16,23 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.nio.file.Path; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; - -import java.nio.file.Path; -import java.util.Random; -import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; /** * */ +@Timeout(30) public class RollingAppenderCronEvery2DirectTest extends AbstractRollingListenerTest { private static final String CONFIG = "log4j-rolling-cron-every2-direct.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java index cdaf9e84620..89b2dbe64e0 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java @@ -16,21 +16,23 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.nio.file.Path; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; - -import java.nio.file.Path; -import java.util.Random; -import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; /** * */ +@Timeout(30) public class RollingAppenderCronEvery2Test extends AbstractRollingListenerTest { private static final String CONFIG = "log4j-rolling-cron-every2.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnStartupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnStartupTest.java index f7a16875446..c3817308364 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnStartupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnStartupTest.java @@ -28,17 +28,17 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configurator; -import org.junit.Test; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * */ +@Timeout(30) public class RollingAppenderCronOnStartupTest { private static final String CONFIG = "log4j-rolling-cron-onStartup.xml"; @@ -82,19 +82,18 @@ public void testAppender() throws Exception { ps = new PrintStream(new FileOutputStream(rolled)); ps.println("This is a line 1"); ps.close(); - assertTrue("Log file does not exist", file.exists()); - assertTrue("Log file does not exist", rolled.exists()); - LoggerContext lc = Configurator.initialize("Test", CONFIG); - final Logger logger = lc.getLogger(RollingAppenderCronOnStartupTest.class); + assertTrue(file.exists(), "Log file does not exist"); + assertTrue(rolled.exists(), "Log file does not exist"); + context = Configurator.initialize("Test", CONFIG); + final Logger logger = context.getLogger(RollingAppenderCronOnStartupTest.class); logger.info("This is line 3"); File[] files = dir.listFiles(); - assertNotNull("No files", files); - assertEquals("Unexpected number of files. Expected 2 but found " + files.length, 2, - files.length); + assertNotNull(files, "No files"); + assertEquals(2, files.length, "Unexpected number of files. Expected 2 but found " + files.length); List lines = Files.readAllLines(file.toPath()); - assertEquals("Unexpected number of lines. Expected 2: Actual: " + lines.size(), 2, lines.size()); + assertEquals(2, lines.size(), "Unexpected number of lines. Expected 2: Actual: " + lines.size()); lines = Files.readAllLines(rolled.toPath()); - assertEquals("Unexpected number of lines. Expected 1: Actual: " + lines.size(), 1, lines.size()); + assertEquals(1, lines.size(), "Unexpected number of lines. Expected 1: Actual: " + lines.size()); } private static void cleanDir(File dir) { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java index 0f5f0039934..3ebe4f91645 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -41,6 +42,7 @@ @Tag("flaky") @Disabled("https://issues.apache.org/jira/browse/LOG4J2-3633") +@Timeout(30) public class RollingAppenderCronOnceADayTest extends AbstractRollingListenerTest { private static final int CRON_DELAY = 10; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java index 20b8bfb293a..1c38c0ac4c9 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java @@ -16,6 +16,14 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CountDownLatch; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.RollingFileAppender; @@ -24,14 +32,7 @@ import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -39,6 +40,7 @@ /** * */ +@Timeout(30) public class RollingAppenderCronTest extends AbstractRollingListenerTest implements PropertyChangeListener { private static final String CONFIG = "log4j-rolling-cron.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCronTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCronTest.java index e700303f412..7e10c18f22d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCronTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCronTest.java @@ -27,10 +27,10 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.appender.RollingFileAppender; - import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; +import org.junit.jupiter.api.Timeout; import org.junit.rules.RuleChain; import static org.junit.Assert.assertTrue; @@ -39,6 +39,7 @@ /** * */ +@Timeout(30) public class RollingAppenderDirectCronTest { private static final String CONFIG = "log4j-rolling-direct-cron.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java index 789cbffb35a..01a0b0b9454 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java @@ -16,6 +16,15 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; @@ -26,26 +35,15 @@ import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertEquals; /** * */ +@Timeout(30) public class RollingAppenderDirectWrite1906Test implements RolloverListener { private static final String CONFIG = "log4j-rolling-direct-1906.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java index 786753f1397..c1e368d5cb2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java @@ -16,9 +16,16 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.RollingFileAppender; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.HtmlLayout; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.util.IOUtils; @@ -28,13 +35,6 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that; import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName; import static org.hamcrest.MatcherAssert.assertThat; @@ -78,9 +78,9 @@ private void checkAppenderWithHtmlLayout(boolean append, final Configuration con try { int count = 100; for (int i = 0; i < count; ++i) { - appender.append(Log4jLogEvent.newBuilder() + appender.append(LogEvent.builder() .setMessage(new SimpleMessage("This is test message number " + i)) - .build() + .get() ); } appender.getManager().flush(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java index 95ce08e4fbb..7743eeb08ac 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java @@ -1,30 +1,39 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE - * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to You under the Apache license, Version 2.0 (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by - * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the license for the specific language - * governing permissions and limitations under the license. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.File; +import java.net.URI; +import java.util.concurrent.CountDownLatch; + import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.RollingFileAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; - -import java.io.File; -import java.net.URI; -import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Timeout; import static org.assertj.core.api.Assertions.assertThat; /** * */ +@Timeout(30) public class RollingAppenderDirectWriteWithReconfigureTest extends AbstractRollingListenerTest { private static final String CONFIG = "log4j-rolling-direct-reconfigure.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupDirectTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupDirectTest.java index 1cb9efd2936..2cc7a2932fd 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupDirectTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderOnStartupDirectTest.java @@ -33,12 +33,12 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configurator; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -55,7 +55,7 @@ public class RollingAppenderOnStartupDirectTest { private static LoggerContext loggerContext; - @BeforeClass + @BeforeAll public static void beforeClass() throws Exception { if (Files.exists(Paths.get("target/onStartup"))) { try (DirectoryStream directoryStream = Files.newDirectoryStream(Paths.get(DIR))) { @@ -86,16 +86,15 @@ public void performTest() throws Exception { ++fileCount; if (path.toFile().getName().startsWith(ROLLED)) { List lines = Files.readAllLines(path); - assertTrue("No messages in " + path.toFile().getName(), lines.size() > 0); - assertTrue("Missing message for " + path.toFile().getName(), - lines.get(0).startsWith(PREFIX)); + assertTrue(lines.size() > 0, "No messages in " + path.toFile().getName()); + assertTrue(lines.get(0).startsWith(PREFIX), "Missing message for " + path.toFile().getName()); } } } - assertEquals("File did not roll", 2, fileCount); + assertEquals(2, fileCount, "File did not roll"); } - @AfterClass + @AfterAll public static void afterClass() throws Exception { Configurator.shutdown(loggerContext); try (DirectoryStream directoryStream = Files.newDirectoryStream(Paths.get(DIR))) { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java index eb3ed629b88..30194ca8c28 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java @@ -16,6 +16,15 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.File; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.RollingFileAppender; @@ -26,15 +35,7 @@ import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - -import java.io.File; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Phaser; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; +import org.junit.jupiter.api.Timeout; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -44,6 +45,7 @@ * create multiple files per directory. */ @Disabled("https://issues.apache.org/jira/browse/LOG4J2-3449") +@Timeout(30) public class RollingDirectSizeTimeNewDirectoryTest implements RolloverListener { private static final String CONFIG = "log4j-rolling-size-time-new-directory.xml"; @@ -98,5 +100,3 @@ public void rolloverComplete(String fileName) { phaser.arriveAndDeregister(); } } - - diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java index f4416fe0132..b880488aaa2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.io.File; +import java.util.Arrays; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.logging.log4j.Logger; @@ -24,19 +29,13 @@ import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.test.junit.CleanUpDirectories; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import org.opentest4j.AssertionFailedError; -import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; +@Timeout(30) public class RollingDirectTimeNewDirectoryTest implements RolloverListener { private static final String CONFIG = "log4j-rolling-folder-direct.xml"; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderUpdateDataTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderUpdateDataTest.java index ac1f552bda5..ae89cfc053d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderUpdateDataTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderUpdateDataTest.java @@ -14,7 +14,6 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.rolling; import org.apache.logging.log4j.Level; @@ -26,9 +25,11 @@ import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; /** * Tests LOG4J2-2009 Rolling appender managers broken on pattern/policy reconfiguration @@ -66,17 +67,17 @@ private ConfigurationBuilder buildConfigurationBuilder(final private LoggerContext loggerContext1 = null; private LoggerContext loggerContext2 = null; - @After - public void after() { - if (loggerContext1 != null) { - loggerContext1.close(); - loggerContext1 = null; - } - if (loggerContext2 != null) { - loggerContext2.close(); - loggerContext2 = null; - } - } + @AfterEach + public void after() { + if (loggerContext1 != null) { + loggerContext1.close(); + loggerContext1 = null; + } + if (loggerContext2 != null) { + loggerContext2.close(); + loggerContext2 = null; + } + } @Test public void testClosingLoggerContext() { @@ -99,26 +100,26 @@ public void testNotClosingLoggerContext() { // rebuild config with date based rollover loggerContext2 = Configurator.initialize(buildConfigB().build()); - Assert.assertNotNull("No LoggerContext", loggerContext2); - Assert.assertSame("Expected same logger context to be returned", loggerContext1, loggerContext2); - validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%i"); + assertNotNull(loggerContext2, "No LoggerContext"); + assertSame(loggerContext1, loggerContext2, "Expected same logger context to be returned"); + validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%i"); } - @Test - public void testReconfigure() { - // initial config with indexed rollover - loggerContext1 = Configurator.initialize(buildConfigA().build()); - validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%i"); + @Test + public void testReconfigure() { + // initial config with indexed rollover + loggerContext1 = Configurator.initialize(buildConfigA().build()); + validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%i"); - // rebuild config with date based rollover - loggerContext1.setConfiguration(buildConfigB().build()); - validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%d{yyyy-MM-dd-HH:mm:ss}.%i"); - } + // rebuild config with date based rollover + loggerContext1.setConfiguration(buildConfigB().build()); + validateAppender(loggerContext1, "target/rolling-update-date/foo.log.%d{yyyy-MM-dd-HH:mm:ss}.%i"); + } private void validateAppender(final LoggerContext loggerContext, final String expectedFilePattern) { final RollingFileAppender appender = loggerContext.getConfiguration().getAppender("fooAppender"); - Assert.assertNotNull(appender); - Assert.assertEquals(expectedFilePattern, appender.getFilePattern()); + assertNotNull(appender); + assertEquals(expectedFilePattern, appender.getFilePattern()); LogManager.getLogger("root").info("just to show it works."); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManagerTest.java index c47d2ecb477..8e570869e5f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManagerTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManagerTest.java @@ -14,16 +14,8 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.rolling; -import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.core.util.Closer; -import org.apache.logging.log4j.core.util.FileUtils; -import org.apache.logging.log4j.core.util.NullOutputStream; -import org.apache.logging.log4j.util.Strings; -import org.junit.Test; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -37,17 +29,19 @@ import java.util.Set; import java.util.concurrent.locks.LockSupport; -import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.beforeNow; -import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasLength; -import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.isEmpty; -import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.lastModified; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.DefaultConfiguration; +import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.util.Strings; +import org.junit.jupiter.api.Test; + +import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.lessThanOrEqualTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * Tests the RollingRandomAccessFileManager class. @@ -63,14 +57,14 @@ public void testWrite_multiplesOfBufferSize() throws IOException { final File file = File.createTempFile("log4j2", "test"); file.deleteOnExit(); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final boolean append = false; final boolean flushNow = false; final long triggerSize = Long.MAX_VALUE; final long initialTime = System.currentTimeMillis(); final TriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy(triggerSize); final RolloverStrategy rolloverStrategy = null; - final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(null, raf, + final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(LoggerContext.getContext(), raf, file.getName(), Strings.EMPTY, os, append, flushNow, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, triggerSize, initialTime, triggerPolicy, rolloverStrategy, null, null, null, null, null, true); @@ -93,14 +87,14 @@ public void testWrite_dataExceedingBufferSize() throws IOException { final File file = File.createTempFile("log4j2", "test"); file.deleteOnExit(); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final boolean append = false; final boolean flushNow = false; final long triggerSize = 0; final long time = System.currentTimeMillis(); final TriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy(triggerSize); final RolloverStrategy rolloverStrategy = null; - final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(null, raf, + final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(LoggerContext.getContext(), raf, file.getName(), Strings.EMPTY, os, append, flushNow, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, triggerSize, time, triggerPolicy, rolloverStrategy, null, null, null, null, null, true); @@ -120,7 +114,7 @@ public void testConfigurableBufferSize() throws IOException { final File file = File.createTempFile("log4j2", "test"); file.deleteOnExit(); try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final boolean append = false; final boolean flushNow = false; final long triggerSize = 0; @@ -129,7 +123,7 @@ public void testConfigurableBufferSize() throws IOException { final int bufferSize = 4 * 1024; assertNotEquals(bufferSize, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE); final RolloverStrategy rolloverStrategy = null; - final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(null, raf, + final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(LoggerContext.getContext(), raf, file.getName(), Strings.EMPTY, os, append, flushNow, bufferSize, triggerSize, time, triggerPolicy, rolloverStrategy, null, null, null, null, null, true); @@ -163,7 +157,8 @@ public void testAppendDoesNotOverwriteExistingFile() throws IOException { // file.getAbsolutePath(), Strings.EMPTY, isAppend, immediateFlush, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, new SizeBasedTriggeringPolicy(Long.MAX_VALUE), // - null, null, null, null, null, null, null); + null, null, null, null, null, null, new DefaultConfiguration()); + assertNotNull(manager); manager.write(bytes, 0, bytes.length, immediateFlush); final int expected = bytes.length * 2; assertThat("appended, not overwritten", file, hasLength(expected)); @@ -185,7 +180,8 @@ public void testFileTimeBasedOnSystemClockWhenAppendIsFalse() throws IOException // file.getAbsolutePath(), Strings.EMPTY, isAppend, true, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, new SizeBasedTriggeringPolicy(Long.MAX_VALUE), // - null, null, null, null, null, null, null); + null, null, null, null, null, null, new DefaultConfiguration()); + assertNotNull(manager); assertTrue(manager.getFileTime() < expectedMax); assertTrue(manager.getFileTime() >= expectedMin); } @@ -203,7 +199,8 @@ public void testFileTimeBasedOnFileModifiedTimeWhenAppendIsTrue() throws IOExcep // file.getAbsolutePath(), Strings.EMPTY, isAppend, true, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, new SizeBasedTriggeringPolicy(Long.MAX_VALUE), // - null, null, null, null, null, null, null); + null, null, null, null, null, null, new DefaultConfiguration()); + assertNotNull(manager); assertThat(file, lastModified(equalTo(manager.getFileTime()))); } @@ -225,6 +222,7 @@ public void testRolloverRetainsFileAttributes() throws Exception { PosixFilePermissions.fromString(filePermissionsString); FileUtils.defineFilePosixAttributeView(file.toPath(), filePermissions, null, null); + final Configuration configuration = new DefaultConfiguration(); // Create the manager. final RolloverStrategy rolloverStrategy = DefaultRolloverStrategy .newBuilder() @@ -232,7 +230,7 @@ public void testRolloverRetainsFileAttributes() throws Exception { .setMin("1") .setFileIndex("max") .setStopCustomActionsOnError(false) - .setConfig(new DefaultConfiguration()) + .setConfig(configuration) .build(); final RollingRandomAccessFileManager manager = RollingRandomAccessFileManager.getRollingRandomAccessFileManager( @@ -248,7 +246,7 @@ public void testRolloverRetainsFileAttributes() throws Exception { filePermissionsString, null, null, - null); + configuration); assertNotNull(manager); manager.initialize(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteActionTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteActionTest.java index 856e835d031..dc0870e579d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteActionTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteActionTest.java @@ -14,7 +14,6 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.rolling.action; import java.nio.file.FileSystems; @@ -25,8 +24,9 @@ import java.util.Collections; import java.util.EnumSet; -import org.apache.logging.log4j.core.test.BasicConfigurationFactory; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.test.BasicConfigurationFactory; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; @@ -45,7 +45,7 @@ private static DeleteAction createAnyFilter(final String path, final boolean fol private static DeleteAction create(final String path, final boolean followLinks, final int maxDepth, final boolean testMode, final PathCondition[] conditions) { - final Configuration config = new BasicConfigurationFactory.BasicConfiguration(); + final Configuration config = new BasicConfigurationFactory.BasicConfiguration(LoggerContext.getContext()); return DeleteAction.createDeleteAction(path, followLinks, maxDepth, testMode, null, conditions, null, config); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModifiedTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModifiedTest.java index 32471d6be13..171af44cac2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModifiedTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModifiedTest.java @@ -14,14 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.rolling.action; +import java.nio.file.attribute.FileTime; + import org.apache.logging.log4j.core.test.appender.rolling.action.DummyFileAttributes; +import org.apache.logging.log4j.core.time.internal.SystemClock; import org.junit.jupiter.api.Test; -import java.nio.file.attribute.FileTime; - import static org.junit.jupiter.api.Assertions.*; /** @@ -29,15 +29,19 @@ */ public class IfLastModifiedTest { + private static IfLastModified.Builder builder() { + return IfLastModified.newBuilder().setClock(new SystemClock()); + } + @Test public void testGetDurationReturnsConstructorValue() { - final IfLastModified filter = IfLastModified.newBuilder().setAge(Duration.parse("P7D")).get(); + final IfLastModified filter = builder().setAge(Duration.parse("P7D")).get(); assertEquals(0, filter.getAge().compareTo(Duration.parse("P7D"))); } @Test public void testAcceptsIfFileAgeEqualToDuration() { - final IfLastModified filter = IfLastModified.newBuilder().setAge(Duration.parse("PT33S")).get(); + final IfLastModified filter = builder().setAge(Duration.parse("PT33S")).get(); final DummyFileAttributes attrs = new DummyFileAttributes(); final long age = 33 * 1000; attrs.lastModified = FileTime.fromMillis(System.currentTimeMillis() - age); @@ -46,7 +50,7 @@ public void testAcceptsIfFileAgeEqualToDuration() { @Test public void testAcceptsIfFileAgeExceedsDuration() { - final IfLastModified filter = IfLastModified.newBuilder().setAge(Duration.parse("PT33S")).get(); + final IfLastModified filter = builder().setAge(Duration.parse("PT33S")).get(); final DummyFileAttributes attrs = new DummyFileAttributes(); final long age = 33 * 1000 + 5; attrs.lastModified = FileTime.fromMillis(System.currentTimeMillis() - age); @@ -55,7 +59,7 @@ public void testAcceptsIfFileAgeExceedsDuration() { @Test public void testDoesNotAcceptIfFileAgeLessThanDuration() { - final IfLastModified filter = IfLastModified.newBuilder().setAge(Duration.parse("PT33S")).get(); + final IfLastModified filter = builder().setAge(Duration.parse("PT33S")).get(); final DummyFileAttributes attrs = new DummyFileAttributes(); final long age = 33 * 1000 - 5; attrs.lastModified = FileTime.fromMillis(System.currentTimeMillis() - age); @@ -65,7 +69,7 @@ public void testDoesNotAcceptIfFileAgeLessThanDuration() { @Test public void testAcceptCallsNestedConditionsOnlyIfPathAccepted() { final CountingCondition counter = new CountingCondition(true); - final IfLastModified filter = IfLastModified.newBuilder() + final IfLastModified filter = builder() .setAge(Duration.parse("PT33S")) .setNestedConditions(counter) .get(); @@ -93,7 +97,7 @@ public void testAcceptCallsNestedConditionsOnlyIfPathAccepted() { @Test public void testBeforeTreeWalk() { final CountingCondition counter = new CountingCondition(true); - final IfLastModified filter = IfLastModified.newBuilder() + final IfLastModified filter = builder() .setAge(Duration.parse("PT33S")) .setNestedConditions(counter, counter, counter) .get(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncAppenderConfigTest_LOG4J2_2032.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncAppenderConfigTest_LOG4J2_2032.java index 8cbee4e4cbc..ae954968049 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncAppenderConfigTest_LOG4J2_2032.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncAppenderConfigTest_LOG4J2_2032.java @@ -22,24 +22,35 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.impl.LogEventFactory; +import org.apache.logging.log4j.core.impl.ReusableLogEventFactory; import org.apache.logging.log4j.core.test.CoreLoggerContexts; -import org.apache.logging.log4j.spi.LoggingSystemProperties; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.message.ReusableMessageFactory; +import org.apache.logging.log4j.plugins.SingletonFactory; import org.apache.logging.log4j.test.junit.CleanUpFiles; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.SetSystemProperty; import static org.junit.jupiter.api.Assertions.assertTrue; @Tag("async") -@SetSystemProperty(key = Log4jProperties.LOG_EVENT_FACTORY_CLASS_NAME, value = "org.apache.logging.log4j.core.impl.ReusableLogEventFactory") -@SetSystemProperty(key = LoggingSystemProperties.LOGGER_MESSAGE_FACTORY_CLASS, value = "org.apache.logging.log4j.message.ReusableMessageFactory") -@SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "AsyncAppenderConfigTest-LOG4J2-2032.xml") public class AsyncAppenderConfigTest_LOG4J2_2032 { + @SingletonFactory + LogEventFactory logEventFactory(final ReusableLogEventFactory factory) { + return factory; + } + + @SingletonFactory + MessageFactory messageFactory(final ReusableMessageFactory factory) { + return factory; + } + @Test @CleanUpFiles("target/AsyncAppenderConfigTest-LOG4J2-2032.log") + @LoggerContextSource("AsyncAppenderConfigTest-LOG4J2-2032.xml") public void doNotProcessPlaceholdersTwice() throws Exception { final File file = new File("target", "AsyncAppenderConfigTest-LOG4J2-2032.log"); assertTrue(!file.exists() || file.delete(), "Deleted old file before test"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlockTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlockTest.java index b213db03837..cef9b3b88a8 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlockTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerClassLoadDeadlockTest.java @@ -17,6 +17,7 @@ package org.apache.logging.log4j.core.async; import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -28,7 +29,7 @@ * Test class loading deadlock condition from the LOG4J2-1457 */ @Tag("async") -@SetSystemProperty(key = Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, value = "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector") +@ContextSelectorType(AsyncLoggerContextSelector.class) @SetSystemProperty(key = Log4jProperties.ASYNC_LOGGER_RING_BUFFER_SIZE, value = "128") @SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "AsyncLoggerConsoleTest.xml") public class AsyncLoggerClassLoadDeadlockTest { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigErrorOnFormat.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigErrorOnFormat.java index a1d640bdf8b..5017958b7de 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigErrorOnFormat.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigErrorOnFormat.java @@ -38,7 +38,6 @@ @Tag("async") @SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "AsyncLoggerConfigErrorOnFormat.xml") -@SetSystemProperty(key = Log4jProperties.LOG_EVENT_FACTORY_CLASS_NAME, value = "org.apache.logging.log4j.core.impl.DefaultLogEventFactory") public class AsyncLoggerConfigErrorOnFormat { @Test diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java index eddb6233aae..9e65e67d4d5 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java @@ -23,7 +23,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.impl.Log4jProperties; @@ -64,15 +64,18 @@ public void testAdditivity() throws Exception { @Test public void testIncludeLocationDefaultsToFalse() { - final LoggerConfig rootLoggerConfig = - AsyncLoggerConfig.RootLogger.createLogger( - null, Level.INFO, null, new AppenderRef[0], null, new DefaultConfiguration(), null); + Configuration configuration = new DefaultConfiguration(); + final LoggerConfig rootLoggerConfig = AsyncLoggerConfig.RootLogger.newAsyncRootBuilder() + .setConfig(configuration) + .setLevel(Level.INFO) + .build(); assertFalse(rootLoggerConfig.isIncludeLocation(), "Include location should default to false for async loggers"); - final LoggerConfig loggerConfig = - AsyncLoggerConfig.createLogger( - false, Level.INFO, "com.foo.Bar", null, new AppenderRef[0], null, new DefaultConfiguration(), - null); + final LoggerConfig loggerConfig = AsyncLoggerConfig.newAsyncBuilder() + .setConfig(configuration) + .setLevel(Level.INFO) + .setLoggerName("com.foo.Bar") + .build(); assertFalse(loggerConfig.isIncludeLocation(), "Include location should default to false for async loggers"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest3.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest3.java index 282651c2d1f..759cc94bc8b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest3.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest3.java @@ -16,9 +16,12 @@ */ package org.apache.logging.log4j.core.async; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; @@ -26,9 +29,6 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.util.HashMap; -import java.util.Map; - @Tag("async") @Tag("sleepy") public class AsyncLoggerConfigTest3 { @@ -46,11 +46,12 @@ public void testNoConcurrentModificationException(final Logger log) throws Excep } final Message msg = new ParameterizedMessage("{}", map); - Log4jLogEvent event = Log4jLogEvent.newBuilder() + LogEvent event = LogEvent.builder() .setLevel(Level.WARN) .setLoggerName(getClass().getName()) .setMessage(msg) - .setTimeMillis(0).build(); + .setTimeMillis(0) + .get(); for (int i = 0; i < 100; i++) { ((AsyncLoggerConfig)((org.apache.logging.log4j.core.Logger) log).get()).callAppenders(event); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigWithAsyncEnabledTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigWithAsyncEnabledTest.java index 65e6af56d4b..b5cdd06a668 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigWithAsyncEnabledTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigWithAsyncEnabledTest.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.test.CoreLoggerContexts; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; @@ -33,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @Tag("async") -@SetSystemProperty(key = Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, value = "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector") +@ContextSelectorType(AsyncLoggerContextSelector.class) @SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "AsyncLoggerConfigTest4.xml") public class AsyncLoggerConfigWithAsyncEnabledTest { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorInitialStateTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorInitialStateTest.java index 70a5214954e..5814747cb9b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorInitialStateTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorInitialStateTest.java @@ -30,7 +30,7 @@ public class AsyncLoggerContextSelectorInitialStateTest { public void testLoggerContextsListInitiallyEmpty() { final Injector injector = DI.createInjector(); injector.init(); - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); assertTrue(selector.getLoggerContexts().isEmpty()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorTest.java index 1a41e3f17e9..de4d28eb8f7 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelectorTest.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.async; +import java.util.List; + import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.plugins.di.DI; import org.apache.logging.log4j.plugins.di.Injector; @@ -23,8 +25,6 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -41,7 +41,7 @@ void setUp() { @Test public void testContextReturnsAsyncLoggerContext() { - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); final LoggerContext context = selector.getContext(FQCN, null, false); assertTrue(context instanceof AsyncLoggerContext); @@ -49,7 +49,7 @@ public void testContextReturnsAsyncLoggerContext() { @Test public void testContext2ReturnsAsyncLoggerContext() { - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); final LoggerContext context = selector.getContext(FQCN, null, false, null); assertTrue(context instanceof AsyncLoggerContext); @@ -57,7 +57,7 @@ public void testContext2ReturnsAsyncLoggerContext() { @Test public void testLoggerContextsReturnsAsyncLoggerContext() { - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); selector.getContext(FQCN, null, false); final List list = selector.getLoggerContexts(); @@ -66,17 +66,17 @@ public void testLoggerContextsReturnsAsyncLoggerContext() { } @Test - public void testContextNameIsAsyncLoggerContextWithClassHashCode() { - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + public void testContextKeyIsAsyncLoggerContextWithClassHashCode() { + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); final LoggerContext context = selector.getContext(FQCN, null, false); final int hash = getClass().getClassLoader().hashCode(); - final String expectedContextName = "AsyncContext@" + Integer.toHexString(hash); - assertEquals(expectedContextName, context.getName()); + final String expectedContextKey = "AsyncContext@" + Integer.toHexString(hash); + assertEquals(expectedContextKey, context.getKey()); } @Test public void testDependentOnClassLoader() { - final AsyncLoggerContextSelector selector = new AsyncLoggerContextSelector(injector); + final AsyncLoggerContextSelector selector = injector.getInstance(AsyncLoggerContextSelector.class); assertTrue(selector.isClassLoaderDependent()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextTest.java index c7f03311602..cd65573a23f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerContextTest.java @@ -17,23 +17,35 @@ package org.apache.logging.log4j.core.async; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.test.categories.AsyncLoggers; -import org.apache.logging.log4j.core.test.CoreLoggerContexts; import org.apache.logging.log4j.core.LoggerContext; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import org.apache.logging.log4j.core.util.Closer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; -@Category(AsyncLoggers.class) +@Tag("async") public class AsyncLoggerContextTest { + private AsyncLoggerContext asyncLoggerContext; + private LoggerContext loggerContext; + + @BeforeEach + void setUp() { + asyncLoggerContext = AsyncLoggerContext.newAsyncBuilder().setName("a").get(); + loggerContext = LoggerContext.newBuilder().setName("a").get(); + } + + @AfterEach + void tearDown() { + Closer.closeAllSilently(loggerContext, asyncLoggerContext); + } + @Test public void testNewInstanceReturnsAsyncLogger() { - final Logger logger = new AsyncLoggerContext("a").newInstance( - new LoggerContext("a"), "a", null); - assertTrue(logger instanceof AsyncLogger); - - CoreLoggerContexts.stopLoggerContext(); // stop async thread + final Logger logger = asyncLoggerContext.newInstance(loggerContext, "a", null); + assertThat(logger).isInstanceOf(AsyncLogger.class); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerCustomSelectorLocationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerCustomSelectorLocationTest.java index d2a3acac6ce..2c4d06503ef 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerCustomSelectorLocationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerCustomSelectorLocationTest.java @@ -16,6 +16,13 @@ */ package org.apache.logging.log4j.core.async; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.net.URI; +import java.util.Collections; +import java.util.List; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; @@ -29,13 +36,6 @@ import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.net.URI; -import java.util.Collections; -import java.util.List; - import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -72,7 +72,8 @@ public void testCustomAsyncSelectorLocation() throws Exception { @Singleton public static final class CustomAsyncContextSelector implements ContextSelector { - private static final LoggerContext CONTEXT = new AsyncLoggerContext("AsyncDefault"); + private static final LoggerContext CONTEXT = AsyncLoggerContext.newAsyncBuilder().setName("AsyncDefault").get(); + @Override public LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext) { return CONTEXT; @@ -83,6 +84,11 @@ public LoggerContext getContext(String fqcn, ClassLoader loader, boolean current return CONTEXT; } + @Override + public LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, final boolean currentContext, final URI configLocation) { + return CONTEXT; + } + @Override public List getLoggerContexts() { return Collections.singletonList(CONTEXT); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java index c40862eba61..914868cf283 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java @@ -17,6 +17,10 @@ package org.apache.logging.log4j.core.async; import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.util.DefaultPropertyResolver; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.SystemPropertiesPropertySource; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; @@ -27,30 +31,38 @@ @Tag("async") public class AsyncLoggerThreadNameStrategyTest { + private final PropertyResolver propertyResolver = new DefaultPropertyResolver(); + private final ThreadNameCachingStrategyFactory factory = new ThreadNameCachingStrategyFactory(propertyResolver); + + @BeforeEach + void setUp() { + propertyResolver.addSource(new SystemPropertiesPropertySource()); + } + @Test public void testDefaultIfNotConfigured() throws Exception { - final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create(); - assertSame(ThreadNameCachingStrategy.DEFAULT_STRATEGY, tns); + final ThreadNameCachingStrategy tns = factory.get(); + assertSame(ThreadNameCachingStrategyFactory.DEFAULT_STRATEGY, tns); } @Test @SetSystemProperty(key = Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, value = "\\%%InValid ") public void testDefaultIfInvalidConfig() throws Exception { - final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create(); - assertSame(ThreadNameCachingStrategy.DEFAULT_STRATEGY, tns); + final ThreadNameCachingStrategy tns = factory.get(); + assertSame(ThreadNameCachingStrategyFactory.DEFAULT_STRATEGY, tns); } @Test @SetSystemProperty(key = Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, value = "CACHED") public void testUseCachedThreadNameIfConfigured() throws Exception { - final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create(); + final ThreadNameCachingStrategy tns = factory.get(); assertSame(ThreadNameCachingStrategy.CACHED, tns); } @Test @SetSystemProperty(key = Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, value = "UNCACHED") public void testUseUncachedThreadNameIfConfigured() throws Exception { - final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create(); + final ThreadNameCachingStrategy tns = factory.get(); assertSame(ThreadNameCachingStrategy.UNCACHED, tns); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerUseAfterShutdownTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerUseAfterShutdownTest.java index 267f9e88e05..5fe773978c8 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerUseAfterShutdownTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerUseAfterShutdownTest.java @@ -21,6 +21,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.test.CoreLoggerContexts; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.AbstractLogger; import org.junit.jupiter.api.Tag; @@ -32,9 +33,9 @@ */ @Tag("async") @Tag("functional") +@ContextSelectorType(AsyncLoggerContextSelector.class) public class AsyncLoggerUseAfterShutdownTest { @Test - @SetSystemProperty(key = Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, value = "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector") @SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "AsyncLoggerTest.xml") public void testNoErrorIfLogAfterShutdown() throws Exception { final Logger log = LogManager.getLogger("com.foo.Bar"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncAppenderTest.java index 0a051ffd792..7c2225dd63c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncAppenderTest.java @@ -16,30 +16,24 @@ */ package org.apache.logging.log4j.core.async; +import java.util.List; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Named; -import org.apache.logging.log4j.plugins.SingletonFactory; -import org.apache.logging.log4j.plugins.di.Injector; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.util.List; -import java.util.concurrent.TimeUnit; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @Tag("async") +@ContextSelectorType(AsyncLoggerContextSelector.class) public class AsyncLoggersWithAsyncAppenderTest { - @SingletonFactory - public ContextSelector contextSelector(final Injector injector) { - return new AsyncLoggerContextSelector(injector); - } - @Test @LoggerContextSource("AsyncLoggersWithAsyncAppenderTest.xml") public void testLoggingWorks(final Logger logger, @Named("List") final ListAppender appender) throws Exception { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java index 3e9388c14dd..6086f383ded 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java @@ -16,30 +16,24 @@ */ package org.apache.logging.log4j.core.async; +import java.util.List; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.test.appender.ListAppender; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Named; -import org.apache.logging.log4j.plugins.SingletonFactory; -import org.apache.logging.log4j.plugins.di.Injector; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.util.List; -import java.util.concurrent.TimeUnit; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @Tag("async") +@ContextSelectorType(AsyncLoggerContextSelector.class) public class AsyncLoggersWithAsyncLoggerConfigTest { - @SingletonFactory - public ContextSelector contextSelector(final Injector injector) { - return new AsyncLoggerContextSelector(injector); - } - @Test @LoggerContextSource("AsyncLoggersWithAsyncLoggerConfigTest.xml") public void testLoggingWorks(final Logger logger, @Named("List") final ListAppender appender) throws Exception { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java index 8820918017c..27db9ff88dc 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java @@ -20,11 +20,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.junit.jupiter.api.AfterEach; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearSystemProperty; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,19 +33,21 @@ * Tests the AsyncQueueFullPolicyFactory class. */ @Tag("async") +@ClearSystemProperty(key = Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY) +@ClearSystemProperty(key = Log4jProperties.ASYNC_LOGGER_DISCARD_THRESHOLD) public class AsyncQueueFullPolicyFactoryTest { + private final Injector injector = DI.createInjector(); + @BeforeEach - @AfterEach - public void resetProperties() { - System.clearProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY); - System.clearProperty(Log4jProperties.ASYNC_LOGGER_DISCARD_THRESHOLD); - PropertiesUtil.getProperties().reload(); + void setUp() { + injector.init(); } @Test public void testCreateReturnsDefaultRouterByDefault() { - final AsyncQueueFullPolicy router = AsyncQueueFullPolicyFactory.create(); + System.clearProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY); + final AsyncQueueFullPolicy router = injector.getInstance(AsyncQueueFullPolicy.class); assertEquals(DefaultAsyncQueueFullPolicy.class, router.getClass()); } @@ -52,22 +55,22 @@ public void testCreateReturnsDefaultRouterByDefault() { public void testCreateReturnsDiscardingRouterIfSpecified() { System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, AsyncQueueFullPolicyFactory.PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER); - assertEquals(DiscardingAsyncQueueFullPolicy.class, AsyncQueueFullPolicyFactory.create().getClass()); + assertEquals(DiscardingAsyncQueueFullPolicy.class, injector.getInstance(AsyncQueueFullPolicy.class).getClass()); System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, DiscardingAsyncQueueFullPolicy.class.getSimpleName()); - assertEquals(DiscardingAsyncQueueFullPolicy.class, AsyncQueueFullPolicyFactory.create().getClass()); + assertEquals(DiscardingAsyncQueueFullPolicy.class, injector.getInstance(AsyncQueueFullPolicy.class).getClass()); System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, DiscardingAsyncQueueFullPolicy.class.getName()); - assertEquals(DiscardingAsyncQueueFullPolicy.class, AsyncQueueFullPolicyFactory.create().getClass()); + assertEquals(DiscardingAsyncQueueFullPolicy.class, injector.getInstance(AsyncQueueFullPolicy.class).getClass()); } @Test public void testCreateDiscardingRouterDefaultThresholdLevelInfo() { System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, AsyncQueueFullPolicyFactory.PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER); - assertEquals(Level.INFO, ((DiscardingAsyncQueueFullPolicy) AsyncQueueFullPolicyFactory.create()). + assertEquals(Level.INFO, ((DiscardingAsyncQueueFullPolicy) injector.getInstance(AsyncQueueFullPolicy.class)). getThresholdLevel()); } @@ -75,7 +78,7 @@ public void testCreateDiscardingRouterDefaultThresholdLevelInfo() { public void testCreateDiscardingRouterCaseInsensitive() { System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, AsyncQueueFullPolicyFactory.PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER.toLowerCase(Locale.ENGLISH)); - assertEquals(Level.INFO, ((DiscardingAsyncQueueFullPolicy) AsyncQueueFullPolicyFactory.create()). + assertEquals(Level.INFO, ((DiscardingAsyncQueueFullPolicy) injector.getInstance(AsyncQueueFullPolicy.class)). getThresholdLevel()); } @@ -87,7 +90,7 @@ public void testCreateDiscardingRouterThresholdLevelCustomizable() { for (final Level level : Level.values()) { System.setProperty(Log4jProperties.ASYNC_LOGGER_DISCARD_THRESHOLD, level.name()); - assertEquals(level, ((DiscardingAsyncQueueFullPolicy) AsyncQueueFullPolicyFactory.create()). + assertEquals(level, ((DiscardingAsyncQueueFullPolicy) injector.getInstance(AsyncQueueFullPolicy.class)). getThresholdLevel()); } } @@ -109,13 +112,13 @@ static class DoesNotImplementInterface { public void testCreateReturnsCustomRouterIfSpecified() { System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, CustomRouterDefaultConstructor.class.getName()); - assertEquals(CustomRouterDefaultConstructor.class, AsyncQueueFullPolicyFactory.create().getClass()); + assertEquals(CustomRouterDefaultConstructor.class, injector.getInstance(AsyncQueueFullPolicy.class).getClass()); } @Test public void testCreateReturnsDefaultRouterIfSpecifiedCustomRouterFails() { System.setProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY, DoesNotImplementInterface.class.getName()); - assertEquals(DefaultAsyncQueueFullPolicy.class, AsyncQueueFullPolicyFactory.create().getClass()); + assertEquals(DefaultAsyncQueueFullPolicy.class, injector.getInstance(AsyncQueueFullPolicy.class).getClass()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncThreadContextTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncThreadContextTest.java index 292437161c2..10a5aac1b1c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncThreadContextTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncThreadContextTest.java @@ -25,21 +25,17 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.ThreadContextTestAccess; -import org.apache.logging.log4j.core.impl.Log4jContextFactory; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.jmx.RingBufferAdmin; import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.test.CoreLoggerContexts; +import org.apache.logging.log4j.core.test.junit.LoggingTestContext; import org.apache.logging.log4j.core.util.NetUtils; -import org.apache.logging.log4j.plugins.di.DI; -import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.spi.DefaultThreadContextMap; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; import org.apache.logging.log4j.test.junit.CleanUpFiles; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Unbox; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Tag; @@ -90,8 +86,7 @@ void init() { System.clearProperty(LoggingSystemProperties.THREAD_CONTEXT_MAP_CLASS); final String PACKAGE = "org.apache.logging.log4j.spi."; System.setProperty(LoggingSystemProperties.THREAD_CONTEXT_MAP_CLASS, PACKAGE + implClassSimpleName()); - PropertiesUtil.getProperties().reload(); - ThreadContextTestAccess.init(); + ThreadContext.init(); } public String implClassSimpleName() { @@ -129,15 +124,15 @@ public void testAsyncLogWritesToLog(final ContextImpl contextImpl, final Mode as } static void doTestAsyncLogWritesToLog(final ContextImpl contextImpl, final Mode asyncMode, final Class testClass) throws Exception { - final Injector injector = DI.createInjector(); - injector.registerBinding(ContextSelector.KEY, injector.getFactory(asyncMode.contextSelectorType)); - injector.init(); - final Log4jContextFactory factory = new Log4jContextFactory(injector); - final String fqcn = testClass.getName(); - final ClassLoader classLoader = testClass.getClassLoader(); - final String name = contextImpl.toString() + ' ' + asyncMode; + final LoggingTestContext testContext = LoggingTestContext.configurer() + .setContextName(contextImpl.name() + ' ' + asyncMode.name()) + .setClassLoader(testClass.getClassLoader()) + .setBootstrap(true) + .setConfigUri(asyncMode.configUri) + .build(); + testContext.init(injector -> injector.registerBinding(ContextSelector.KEY, injector.getFactory(asyncMode.contextSelectorType))); contextImpl.init(); - final LoggerContext context = factory.getContext(fqcn, classLoader, null, false, asyncMode.configUri, name); + final LoggerContext context = testContext.getLoggerContext(); runTest(context, contextImpl, asyncMode); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java index a87cfc169ca..981ae242bd3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelectorTest.java @@ -22,6 +22,7 @@ import org.apache.logging.log4j.core.impl.Log4jContextFactory; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.test.junit.ContextSelectorType; +import org.apache.logging.log4j.spi.LoggerContextFactory; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -34,25 +35,29 @@ public class BasicAsyncLoggerContextSelectorTest { private static final String FQCN = BasicAsyncLoggerContextSelectorTest.class.getName(); + private static ContextSelector getSelector() { + final LoggerContextFactory contextFactory = LogManager.getFactory(); + assertThat(contextFactory).isInstanceOf(Log4jContextFactory.class); + return ((Log4jContextFactory) contextFactory).getSelector(); + } + @Test public void testContextReturnsAsyncLoggerContext() { - final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); + final ContextSelector selector = getSelector(); final LoggerContext context = selector.getContext(FQCN, null, false); - - assertTrue(context instanceof AsyncLoggerContext); + assertThat(context).isInstanceOf(AsyncLoggerContext.class); } @Test public void testContext2ReturnsAsyncLoggerContext() { - final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); + final ContextSelector selector = getSelector(); final LoggerContext context = selector.getContext(FQCN, null, false, null); - - assertTrue(context instanceof AsyncLoggerContext); + assertThat(context).isInstanceOf(AsyncLoggerContext.class); } @Test public void testLoggerContextsReturnsAsyncLoggerContext() { - final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); + final ContextSelector selector = getSelector(); assertThat(selector.getLoggerContexts()).hasExactlyElementsOfTypes(AsyncLoggerContext.class); selector.getContext(FQCN, null, false); @@ -62,14 +67,14 @@ public void testLoggerContextsReturnsAsyncLoggerContext() { @Test public void testContextNameIsAsyncDefault() { - final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); + final ContextSelector selector = getSelector(); final LoggerContext context = selector.getContext(FQCN, null, false); - assertEquals("AsyncDefault", context.getName()); + assertThat(context.getName()).isEqualTo("AsyncDefault"); } @Test public void testDependentOnClassLoader() { - final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); + final ContextSelector selector = getSelector(); assertFalse(selector.isClassLoaderDependent()); } @@ -80,9 +85,11 @@ public void testFactoryIsNotDependentOnClassLoader() { @Test public void testLogManagerShutdown() { - LoggerContext context = (LoggerContext) LogManager.getContext(); - assertEquals(LifeCycle.State.STARTED, context.getState()); + final var loggerContext = LogManager.getContext(); + assertThat(loggerContext).isInstanceOf(LoggerContext.class); + LoggerContext context = (LoggerContext) loggerContext; + assertTrue(context.isStarted()); LogManager.shutdown(); - assertEquals(LifeCycle.State.STOPPED, context.getState()); + assertTrue(context.isStopped()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java index e1892b9a2cb..27f2129455a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java @@ -16,13 +16,17 @@ */ package org.apache.logging.log4j.core.async; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; 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.core.impl.Log4jLogEvent; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginAttribute; @@ -30,19 +34,12 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - /** * Appender that can be halted and resumed, for testing queue-full scenarios. */ @Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) @Plugin("Blocking") public class BlockingAppender extends AbstractAppender { - private static final long serialVersionUID = 1L; // logEvents may be nulled to disable event tracking, this is useful in scenarios testing garbage collection. public List logEvents = new CopyOnWriteArrayList<>(); public CountDownLatch countDownLatch = null; @@ -60,7 +57,7 @@ public void append(final LogEvent event) { // may be a reusable event, make a copy, don't keep a reference to the original event List events = logEvents; if (events != null) { - events.add(Log4jLogEvent.createMemento(event)); + events.add(event.copy()); } if (countDownLatch == null) { @@ -79,7 +76,7 @@ public static BlockingAppender createAppender( @PluginAttribute @Required(message = "No name provided for HangingAppender") final String name, - @PluginElement final Layout layout, + @PluginElement final Layout layout, @PluginElement final Filter filter) { return new BlockingAppender(name); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java index 44edc4a5499..f01bf80f543 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java @@ -21,49 +21,21 @@ import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.test.categories.AsyncLoggers; -import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.core.test.junit.ContextSelectorType; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.spi.ExtendedLogger; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; /** * Tests LOG4J2-1688 Multiple loggings of arguments are setting these arguments to null. */ -@RunWith(BlockJUnit4ClassRunner.class) -@Category(AsyncLoggers.class) +@ContextSelectorType(AsyncLoggerContextSelector.class) +@LoggerContextSource("log4j-list.xml") public class Log4j2Jira1688AsyncTest { - - @BeforeClass - public static void beforeClass() { - System.setProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, - AsyncLoggerContextSelector.class.getName()); - } - - @AfterClass - public static void afterClass() { - System.clearProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME); - } - - @Rule - public LoggerContextRule context = new LoggerContextRule("log4j-list.xml"); - private ListAppender listAppender; - - @Before - public void before() throws Exception { - listAppender = context.getListAppender("List"); - } - private static Object[] createArray(final int size) { final Object[] args = new Object[size]; for (int i = 0; i < args.length; i++) { @@ -73,20 +45,19 @@ private static Object[] createArray(final int size) { } @Test - public void testLog4j2Only() throws InterruptedException { - final ExtendedLogger log4JLogger = context.getLogger(this.getClass()); + public void testLog4j2Only(@Named("List") final ListAppender listAppender, final ExtendedLogger logger) throws InterruptedException { final int limit = 11; // more than unrolled varargs final Object[] args = createArray(limit); final Object[] originalArgs = Arrays.copyOf(args, args.length); listAppender.countDownLatch = new CountDownLatch(1); - log4JLogger.logIfEnabled("test", Level.ERROR, null, "test {}", args); + logger.logIfEnabled("test", Level.ERROR, null, "test {}", args); listAppender.countDownLatch.await(1, TimeUnit.SECONDS); - assertArrayEquals(Arrays.toString(args), originalArgs, args); + assertArrayEquals(originalArgs, args, Arrays.toString(args)); - log4JLogger.logIfEnabled("test", Level.ERROR, null, "test {}", args); - assertArrayEquals(Arrays.toString(args), originalArgs, args); + logger.logIfEnabled("test", Level.ERROR, null, "test {}", args); + assertArrayEquals(originalArgs, args, Arrays.toString(args)); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAbstractTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAbstractTest.java index b3d54bfd4e9..29d6bc2875f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAbstractTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAbstractTest.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.async; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -29,8 +28,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AsyncAppender; import org.apache.logging.log4j.core.config.LoggerConfig; - -import com.lmax.disruptor.dsl.Disruptor; +import org.opentest4j.AssertionFailedError; /** * Tests queue full scenarios abstract superclass. @@ -84,7 +82,7 @@ public String toString() { } } - static Stack transform(final List logEvents) { + static Stack transform(final List logEvents) { final List filtered = new ArrayList<>(logEvents.size()); for (LogEvent event : logEvents) { filtered.add(event.getMessage().getFormattedMessage()); @@ -97,33 +95,17 @@ static Stack transform(final List logEvents) { static long asyncRemainingCapacity(Logger logger) { if (logger instanceof AsyncLogger) { - try { - Field f = field(AsyncLogger.class, "loggerDisruptor"); - return ((AsyncLoggerDisruptor) f.get(logger)).getDisruptor().getRingBuffer().remainingCapacity(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } else { - LoggerConfig loggerConfig = ((org.apache.logging.log4j.core.Logger) logger).get(); - if (loggerConfig instanceof AsyncLoggerConfig) { - try { - Object delegate = field(AsyncLoggerConfig.class, "delegate").get(loggerConfig); - return ((Disruptor) field(AsyncLoggerConfigDisruptor.class, "disruptor").get(delegate)).getRingBuffer().remainingCapacity(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } else { - Appender async = loggerConfig.getAppenders().get("async"); - if (async instanceof AsyncAppender) { - return ((AsyncAppender) async).getQueueCapacity(); - } - } + return ((AsyncLogger) logger).getAsyncLoggerDisruptor().getDisruptor().getRingBuffer().remainingCapacity(); } - throw new IllegalStateException("Neither Async Loggers nor AsyncAppender are configured"); - } - private static Field field(Class c, String name) throws NoSuchFieldException { - Field f = c.getDeclaredField(name); - f.setAccessible(true); - return f; + LoggerConfig loggerConfig = ((org.apache.logging.log4j.core.Logger) logger).get(); + if (loggerConfig instanceof AsyncLoggerConfig) { + final AsyncLoggerConfigDelegate delegate = ((AsyncLoggerConfig) loggerConfig).getAsyncLoggerConfigDelegate(); + return ((AsyncLoggerConfigDisruptor) delegate).getDisruptor().getRingBuffer().remainingCapacity(); + } + Appender async = loggerConfig.getAppenders().get("async"); + if (async instanceof AsyncAppender) { + return ((AsyncAppender) async).getQueueCapacity(); + } + throw new AssertionFailedError("Neither Async Loggers nor AsyncAppender are configured"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAsyncLoggerConfigLoggingFromToStringTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAsyncLoggerConfigLoggingFromToStringTest.java index 17b5081b33f..39da3732c18 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAsyncLoggerConfigLoggingFromToStringTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/QueueFullAsyncLoggerConfigLoggingFromToStringTest.java @@ -28,7 +28,7 @@ import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.status.StatusData; import org.apache.logging.log4j.status.StatusLogger; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; @@ -45,6 +45,7 @@ */ @Tag("async") @DisabledOnOs(value = OS.WINDOWS, disabledReason = "https://issues.apache.org/jira/browse/LOG4J2-3513") +@Disabled("FIXME: infinite loop") @SetSystemProperty(key = Log4jProperties.ASYNC_CONFIG_RING_BUFFER_SIZE, value = "128") public class QueueFullAsyncLoggerConfigLoggingFromToStringTest extends QueueFullAbstractTest { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index 2971d1ebb43..d3292d54e3c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -16,26 +16,24 @@ */ package org.apache.logging.log4j.core.async; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; 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.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.impl.ContextDataFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; +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.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -50,6 +48,10 @@ @Tag("async") public class RingBufferLogEventTest { + private final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + private final ContextDataInjector contextDataInjector = ThreadContextDataInjector.create(contextDataFactory); + private final NanoClock nanoClock = new DummyNanoClock(1); + @Test public void testToImmutable() { final LogEvent logEvent = new RingBufferLogEvent(); @@ -75,7 +77,8 @@ public void testIsPopulated() { final String threadName = null; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(), + nanoClock, contextDataFactory, contextDataInjector); assertTrue(evt.isPopulated()); @@ -97,7 +100,8 @@ public void testGetLevelReturnsOffIfNullLevelSet() { final String threadName = null; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(), + nanoClock, contextDataFactory, contextDataInjector); assertEquals(Level.OFF, evt.getLevel()); } @@ -114,7 +118,8 @@ public void testGetMessageReturnsNonNullMessage() { final String threadName = null; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(), + nanoClock, contextDataFactory, contextDataInjector); assertNotNull(evt.getMessage()); } @@ -131,51 +136,12 @@ public void testGetMillisReturnsConstructorMillisForNormalMessage() { final String threadName = null; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(123, 456), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(123, 456), + nanoClock, contextDataFactory, contextDataInjector); assertEquals(123, evt.getTimeMillis()); assertEquals(456, evt.getInstant().getNanoOfMillisecond()); } - @SuppressWarnings("BanSerializableRead") - @Test - public void testSerializationDeserialization() throws IOException, ClassNotFoundException { - final RingBufferLogEvent evt = new RingBufferLogEvent(); - final String loggerName = "logger.name"; - final Marker marker = null; - final String fqcn = "f.q.c.n"; - final Level level = Level.TRACE; - final Message data = new SimpleMessage("message"); - final Throwable t = new InternalError("not a real error"); - final ContextStack contextStack = null; - final String threadName = "main"; - final StackTraceElement location = null; - evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, - new FixedPreciseClock(12345, 678), new DummyNanoClock(1)); - ((StringMap) evt.getContextData()).putValue("key", "value"); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(evt); - - final ObjectInputStream in = new FilteredObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - final RingBufferLogEvent other = (RingBufferLogEvent) in.readObject(); - assertEquals(loggerName, other.getLoggerName()); - assertEquals(marker, other.getMarker()); - assertEquals(fqcn, other.getLoggerFqcn()); - assertEquals(level, other.getLevel()); - assertEquals(data, other.getMessage()); - assertNull(other.getThrown(), "null after serialization"); - assertEquals(new ThrowableProxy(t), other.getThrownProxy()); - assertEquals(evt.getContextData(), other.getContextData()); - assertEquals(contextStack, other.getContextStack()); - assertEquals(threadName, other.getThreadName()); - assertEquals(location, other.getSource()); - assertEquals(12345, other.getTimeMillis()); - assertEquals(678, other.getInstant().getNanoOfMillisecond()); - } - - @SuppressWarnings("deprecation") @Test public void testCreateMementoReturnsCopy() { final RingBufferLogEvent evt = new RingBufferLogEvent(); @@ -189,7 +155,8 @@ public void testCreateMementoReturnsCopy() { final String threadName = "main"; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, data, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), + nanoClock, contextDataFactory, contextDataInjector); ((StringMap) evt.getContextData()).putValue("key", "value"); final LogEvent actual = evt.createMemento(); @@ -225,7 +192,8 @@ public void testCreateMementoRetainsParametersAndFormat() { final String threadName = "main"; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, message, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), + nanoClock, contextDataFactory, contextDataInjector); ((StringMap) evt.getContextData()).putValue("key", "value"); final Message actual = evt.createMemento().getMessage(); @@ -254,7 +222,8 @@ public void testMementoReuse() { final String threadName = "main"; final StackTraceElement location = null; evt.setValues(null, loggerName, marker, fqcn, level, message, t, (StringMap) evt.getContextData(), - contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), new DummyNanoClock(1)); + contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), + nanoClock, contextDataFactory, contextDataInjector); ((StringMap) evt.getContextData()).putValue("key", "value"); final Message memento1 = evt.memento(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/PerfTestDriver.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/PerfTestDriver.java index 396dc1df8cc..d3d8301599c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/PerfTestDriver.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/PerfTestDriver.java @@ -87,7 +87,7 @@ List processArguments(final String java) { // args.add("-XX:+PrintGCApplicationConcurrentTime"); // args.add("-XX:+PrintSafepointStatistics"); - args.add("-D" + Log4jProperties.CONFIG_V1_FILE_NAME + '=' + log4jConfig); // 1.2 + args.add("-D" + Log4jProperties.CONFIG_V1_LOCATION + '=' + log4jConfig); // 1.2 args.add("-D" + Log4jProperties.CONFIG_LOCATION + '=' + log4jConfig); // 2.x args.add("-Dlogback.configurationFile=" + log4jConfig);// logback diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/ResponseTimeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/ResponseTimeTest.java index efeaa4917ee..5f4cb1ffc7c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/ResponseTimeTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/ResponseTimeTest.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.async.DefaultAsyncQueueFullPolicy; import org.apache.logging.log4j.core.async.EventRoute; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.core.util.Loader; import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; @@ -143,7 +143,7 @@ public static void main(final String[] args) throws Exception { runLatencyTest(logger, WARMUP_DURATION_MILLIS, WARMUP_COUNT, loadMessagesPerSec, idleStrategy, warmupServiceTmHistograms, warmupResponseTmHistograms, threadCount); System.out.println("-----------------Warmup done. load=" + loadMessagesPerSec); - if (!Constants.ENABLE_DIRECT_ENCODERS || !isThreadLocalsEnabled()) { + if (!GarbageFreeConfiguration.getDefaultConfiguration().isDirectEncodersEnabled() || !isThreadLocalsEnabled()) { //System.gc(); //Thread.sleep(5000); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/AppenderControlArraySetTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/AppenderControlArraySetTest.java index e75dd24ee46..12ff5d5b598 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/AppenderControlArraySetTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/AppenderControlArraySetTest.java @@ -16,14 +16,14 @@ */ package org.apache.logging.log4j.core.config; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.test.appender.FailOnceAppender; import org.junit.jupiter.api.Test; -import java.util.HashMap; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.*; /** @@ -38,7 +38,7 @@ public void testInitiallyEmpty() throws Exception { } private AppenderControl createControl(final String name) { - final Appender appender = FailOnceAppender.createAppender(name, null); + final Appender appender = FailOnceAppender.newBuilder().setName(name).get(); return new AppenderControl(appender, Level.INFO, null); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java index 6db5c0f14e7..fce9bf9a16e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java @@ -14,9 +14,16 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.config; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; @@ -24,22 +31,16 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.filter.ThreadContextMapFilter; -import org.apache.logging.log4j.test.junit.CleanUpFiles; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.test.junit.CleanUpFiles; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - import static org.apache.logging.log4j.util.Unbox.box; -import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; @CleanUpFiles({ "target/test-xml.log", @@ -62,32 +63,39 @@ static void checkConfiguration(final LoggerContext context) { final Configuration configuration = context.getConfiguration(); final Map appenders = configuration.getAppenders(); // these used to be separate tests - assertAll(() -> assertNotNull(appenders), - () -> assertEquals(3, appenders.size()), - () -> assertNotNull(configuration.getLoggerContext()), - () -> assertEquals(configuration.getRootLogger(), configuration.getLoggerConfig(Strings.EMPTY)), - () -> assertThrows(NullPointerException.class, () -> configuration.getLoggerConfig(null))); + assertAll( + () -> assertThat(appenders) + .isNotNull() + .hasSize(3), + () -> assertThat(configuration.getLoggerContext()) + .isNotNull(), + () -> assertThat(configuration.getRootLogger()) + .isEqualTo(configuration.getLoggerConfig(Strings.EMPTY)), + () -> assertThatThrownBy(() -> configuration.getLoggerConfig(null)) + .isInstanceOf(NullPointerException.class) + ); final Logger logger = context.getLogger(LOGGER_NAME); - assertEquals(Level.DEBUG, logger.getLevel()); + assertThat(logger.getLevel()).isEqualTo(Level.DEBUG); + assertThat(logger.filterCount()).isEqualTo(1); - assertEquals(1, logger.filterCount()); final Iterator filterIterator = logger.getFilters(); - assertTrue(filterIterator.hasNext()); - assertTrue(filterIterator.next() instanceof ThreadContextMapFilter); + assertThat(filterIterator).hasNext(); + assertThat(filterIterator.next()).isInstanceOf(ThreadContextMapFilter.class); final Appender appender = appenders.get(APPENDER_NAME); - assertTrue(appender instanceof ConsoleAppender); - assertEquals(APPENDER_NAME, appender.getName()); + assertThat(appender).isInstanceOf(ConsoleAppender.class); + assertThat(appender.getName()).isEqualTo(APPENDER_NAME); } static void checkFileLogger(final LoggerContext context, final Path logFile) throws IOException { final long currentThreadId = Thread.currentThread().getId(); final Logger logger = context.getLogger(FILE_LOGGER_NAME); logger.debug("Greetings from ConfigurationFactoryTest in thread#{}", box(currentThreadId)); + assertThat(logFile).exists(); final List lines = Files.readAllLines(logFile); - assertEquals(1, lines.size()); - assertTrue(lines.get(0).endsWith(Long.toString(currentThreadId))); + assertThat(lines).hasSize(1); + assertThat(lines.get(0)).endsWith(Long.toString(currentThreadId)); } @Test diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java index 9182e0189e7..6ab21852f39 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java @@ -14,13 +14,8 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.config; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.management.ManagementFactory; @@ -31,10 +26,14 @@ import java.nio.file.Paths; import org.apache.logging.log4j.core.net.UrlConnectionFactory; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.junit.jupiter.api.Test; import com.sun.management.UnixOperatingSystemMXBean; +import static org.junit.jupiter.api.Assertions.*; + public class ConfigurationSourceTest { @Test @@ -46,7 +45,7 @@ public void testJira_LOG4J2_2770_byteArray() throws Exception { /** * Checks if the usage of 'jar:' URLs does not increase the file descriptor * count and the jar file can be deleted. - * + * * @throws Exception */ @Test @@ -56,7 +55,10 @@ public void testNoJarFileLeak() throws Exception { Files.copy(original, copy); final URL jarUrl = new URL("jar:" + copy.toUri().toURL() + "!/config/console.xml"); final long expected = getOpenFileDescriptorCount(); - UrlConnectionFactory.createConnection(jarUrl).getInputStream().close(); + final Injector injector = DI.createInjector(); + injector.init(); + final UrlConnectionFactory urlConnectionFactory = injector.getInstance(UrlConnectionFactory.class); + urlConnectionFactory.openConnection(jarUrl).getInputStream().close(); // This can only fail on UNIX assertEquals(expected, getOpenFileDescriptorCount()); // This can only fail on Windows diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java index af36b0d36b7..29eb3eddfc2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.config; import java.io.IOException; -import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -28,12 +27,14 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.config.xml.XmlConfiguration; +import org.apache.logging.log4j.core.impl.LogEventFactory; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.status.StatusConsoleListener; import org.apache.logging.log4j.status.StatusListener; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.test.junit.CleanUpFiles; +import org.apache.logging.log4j.util.PropertyResolver; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; @@ -62,7 +63,7 @@ public void testConfig(final LoggerContext ctx) throws IOException { break; } } - final Layout layout = PatternLayout.newBuilder() + final Layout layout = PatternLayout.newBuilder() .setPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) .setConfiguration(config) .build(); @@ -81,9 +82,13 @@ public void testConfig(final LoggerContext ctx) throws IOException { config.addAppender(appender); final AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); final AppenderRef[] refs = new AppenderRef[] {ref}; - - final LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, "org.apache.logging.log4j", - "true", refs, null, config, null ); + final LoggerConfig loggerConfig = LoggerConfig.newBuilder() + .setLevel(Level.INFO) + .setLoggerName("org.apache.logging.log4j") + .setIncludeLocation("true") + .setRefs(refs) + .setConfig(config) + .build(); loggerConfig.addAppender(appender, null, null); config.addLogger("org.apache.logging.log4j", loggerConfig); ctx.updateLoggers(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java index d677b63903a..6678d9037e2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java @@ -14,19 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.config; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -34,107 +32,111 @@ @LoggerContextSource("log4j2-2134.yml") public class JiraLog4j2_2134Test { - @Test - public void testRefresh() { - Logger log = LogManager.getLogger(this.getClass()); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - PatternLayout layout = PatternLayout.newBuilder() - // @formatter:off - .setPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) - .setConfiguration(config) - .build(); - // @formatter:on - Appender appender = FileAppender.newBuilder().setFileName("target/test.log").setLayout(layout) - .setConfiguration(config).setBufferSize(4000).setName("File").build(); - // appender.start(); - config.addAppender(appender); - AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); - AppenderRef[] refs = new AppenderRef[] { ref }; - LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, "testlog4j2refresh", "true", refs, - null, config, null); - loggerConfig.addAppender(appender, null, null); - config.addLogger("testlog4j2refresh", loggerConfig); - ctx.stop(); - ctx.start(config); + @Test + public void testRefresh(final LoggerContext ctx) { + Logger log = ctx.getLogger(this.getClass()); + final Configuration config = ctx.getConfiguration(); + PatternLayout layout = PatternLayout.newBuilder() + // @formatter:off + .setPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) + .setConfiguration(config) + .build(); + // @formatter:on + Appender appender = FileAppender.newBuilder().setFileName("target/test.log").setLayout(layout) + .setConfiguration(config).setBufferSize(4000).setName("File").build(); + // appender.start(); + config.addAppender(appender); + AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); + AppenderRef[] refs = new AppenderRef[] { ref }; + final LoggerConfig loggerConfig = LoggerConfig.newBuilder() + .setLevel(Level.INFO) + .setLoggerName("testlog4j2refresh") + .setIncludeLocation("true") + .setRefs(refs) + .setConfig(config) + .get(); + loggerConfig.addAppender(appender, null, null); + config.addLogger("testlog4j2refresh", loggerConfig); + ctx.stop(); + ctx.start(config); - assertDoesNotThrow(() -> log.error("Info message")); - } + assertDoesNotThrow(() -> log.error("Info message")); + } - @Test - public void testRefreshMinimalCodeStart() { - Logger log = LogManager.getLogger(this.getClass()); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - ctx.start(config); + @Test + public void testRefreshMinimalCodeStart(final LoggerContext ctx) { + Logger log = ctx.getLogger(this.getClass()); + final Configuration config = ctx.getConfiguration(); + ctx.start(config); - assertDoesNotThrow(() -> log.error("Info message")); - } + assertDoesNotThrow(() -> log.error("Info message")); + } - @Test - public void testRefreshMinimalCodeStopStart() { - Logger log = LogManager.getLogger(this.getClass()); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - ctx.stop(); - ctx.start(); + @Test + public void testRefreshMinimalCodeStopStart(final LoggerContext ctx) { + Logger log = ctx.getLogger(this.getClass()); + ctx.stop(); + ctx.start(); - assertDoesNotThrow(() -> log.error("Info message")); - } + assertDoesNotThrow(() -> log.error("Info message")); + } - @Test - public void testRefreshMinimalCodeStopStartConfig() { - Logger log = LogManager.getLogger(this.getClass()); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - ctx.stop(); - ctx.start(config); + @Test + public void testRefreshMinimalCodeStopStartConfig(final LoggerContext ctx) { + Logger log = ctx.getLogger(this.getClass()); + final Configuration config = ctx.getConfiguration(); + ctx.stop(); + ctx.start(config); - assertDoesNotThrow(() -> log.error("Info message")); - } + assertDoesNotThrow(() -> log.error("Info message")); + } - @SuppressWarnings("deprecation") - @Test - public void testRefreshDeprecatedApis() { - Logger log = LogManager.getLogger(this.getClass()); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - PatternLayout layout = PatternLayout.newBuilder() - .setPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) - .setPatternSelector(null) - .setConfiguration(config) - .setRegexReplacement(null) - .setCharset(null) - .setAlwaysWriteExceptions(false) - .setNoConsoleNoAnsi(false) - .setHeader(null) - .setFooter(null) - .build(); - // @formatter:off - Appender appender = FileAppender.newBuilder() - .setFileName("target/test.log") - .setAppend(false) - .setLocking(false) - .setName("File") - .setImmediateFlush(true) - .setIgnoreExceptions(false) - .setBufferedIo(false) - .setBufferSize(4000) - .setLayout(layout) - .setAdvertise(false) - .setConfiguration(config) - .build(); + @Test + public void testRefreshDeprecatedApis(final LoggerContext ctx) { + Logger log = ctx.getLogger(this.getClass()); + final Configuration config = ctx.getConfiguration(); + PatternLayout layout = PatternLayout.newBuilder() + .setPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) + .setPatternSelector(null) + .setConfiguration(config) + .setRegexReplacement(null) + .setCharset(null) + .setAlwaysWriteExceptions(false) + .setNoConsoleNoAnsi(false) + .setHeader(null) + .setFooter(null) + .build(); + // @formatter:off + Appender appender = FileAppender.newBuilder() + .setFileName("target/test.log") + .setAppend(false) + .setLocking(false) + .setName("File") + .setImmediateFlush(true) + .setIgnoreExceptions(false) + .setBufferedIo(false) + .setBufferSize(4000) + .setLayout(layout) + .setAdvertise(false) + .setConfiguration(config) + .build(); // @formatter:on - appender.start(); - config.addAppender(appender); - AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); - AppenderRef[] refs = new AppenderRef[] { ref }; - LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, "testlog4j2refresh", "true", refs, - null, config, null); - loggerConfig.addAppender(appender, null, null); - config.addLogger("testlog4j2refresh", loggerConfig); - ctx.stop(); - ctx.start(config); + appender.start(); + config.addAppender(appender); + AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); + AppenderRef[] refs = new AppenderRef[] { ref }; + final LoggerConfig loggerConfig = LoggerConfig.newBuilder() + .setLevel(Level.INFO) + .setLoggerName("testlog4j2refresh") + .setIncludeLocation("true") + .setRefs(refs) + .setConfig(config) + .get(); + loggerConfig.addAppender(appender, null, null); + config.addLogger("testlog4j2refresh", loggerConfig); + ctx.stop(); + ctx.start(config); - assertDoesNotThrow(() -> log.error("Info message")); - } + assertDoesNotThrow(() -> log.error("Info message")); + } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java index db7285f562a..e2c1cb452df 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java @@ -1,4 +1,4 @@ -package org.apache.logging.log4j.core.config;/* +/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -14,15 +14,18 @@ * See the license for the specific language governing permissions and * limitations under the license. */ +package org.apache.logging.log4j.core.config; + +import java.util.HashSet; +import java.util.List; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.impl.Log4jLogEvent.Builder; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.Cast; import org.junit.jupiter.api.Test; -import java.util.HashSet; -import java.util.List; - import static org.junit.jupiter.api.Assertions.*; /** @@ -31,11 +34,16 @@ public class LoggerConfigTest { private static LoggerConfig createForProperties(final Property[] properties) { - return LoggerConfig.createLogger(true, Level.INFO, "name", "false", new AppenderRef[0], properties, - new NullConfiguration(), null); + return LoggerConfig.newBuilder() + .setAdditivity(true) + .setLevel(Level.INFO) + .setLoggerName("name") + .setIncludeLocation("false") + .setProperties(properties) + .setConfig(new NullConfiguration()) + .get(); } - @SuppressWarnings({"deprecation"}) @Test public void testPropertiesWithoutSubstitution() { assertNull(createForProperties(null).getPropertyList(), "null propertiesList"); @@ -47,12 +55,12 @@ public void testPropertiesWithoutSubstitution() { final LoggerConfig loggerConfig = createForProperties(all); final List list = loggerConfig.getPropertyList(); assertEquals(new HashSet<>(list), - new HashSet<>(loggerConfig.getPropertyList()), "map and list contents equal"); + new HashSet<>(loggerConfig.getPropertyList()), "map and list contents equal"); final Object[] actualList = new Object[1]; loggerConfig.setLogEventFactory((loggerName, marker, fqcn, level, data, properties, t) -> { actualList[0] = properties; - return new Builder().setTimeMillis(System.currentTimeMillis()).build(); + return LogEvent.builder().setTimeMillis(System.currentTimeMillis()).get(); }); loggerConfig.log("name", "fqcn", null, Level.INFO, new SimpleMessage("msg"), null); assertSame(list, actualList[0], "propertiesList passed in as is if no substitutions required"); @@ -67,18 +75,17 @@ public void testPropertiesWithSubstitution() { final LoggerConfig loggerConfig = createForProperties(all); final List list = loggerConfig.getPropertyList(); assertEquals(new HashSet<>(list), - new HashSet<>(loggerConfig.getPropertyList()), "map and list contents equal"); + new HashSet<>(loggerConfig.getPropertyList()), "map and list contents equal"); final Object[] actualListHolder = new Object[1]; loggerConfig.setLogEventFactory((loggerName, marker, fqcn, level, data, properties, t) -> { actualListHolder[0] = properties; - return new Builder().setTimeMillis(System.currentTimeMillis()).build(); + return LogEvent.builder().setTimeMillis(System.currentTimeMillis()).get(); }); loggerConfig.log("name", "fqcn", null, Level.INFO, new SimpleMessage("msg"), null); assertNotSame(list, actualListHolder[0], "propertiesList with substitutions"); - @SuppressWarnings("unchecked") - final List actualList = (List) actualListHolder[0]; + final List actualList = Cast.cast(actualListHolder[0]); for (int i = 0; i < list.size(); i++) { assertEquals(list.get(i).getName(), actualList.get(i).getName(), "name[" + i + "]"); @@ -89,17 +96,17 @@ public void testPropertiesWithSubstitution() { @Test public void testLevel() { - Configuration configuration = new DefaultConfiguration(); + Configuration configuration = new DefaultConfiguration(LoggerContext.getContext()); LoggerConfig config1 = LoggerConfig.newBuilder() - .withLoggerName("org.apache.logging.log4j.test") - .withLevel(Level.ERROR) - .withAdditivity(false) - .withConfig(configuration) + .setLoggerName("org.apache.logging.log4j.test") + .setLevel(Level.ERROR) + .setAdditivity(false) + .setConfig(configuration) .build(); LoggerConfig config2 = LoggerConfig.newBuilder() - .withLoggerName("org.apache.logging.log4j") - .withAdditivity(false) - .withConfig(configuration) + .setLoggerName("org.apache.logging.log4j") + .setAdditivity(false) + .setConfig(configuration) .build(); config1.setParent(config2); assertEquals(config1.getLevel(), Level.ERROR, "Unexpected Level"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/NestedLoggerConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/NestedLoggerConfigTest.java index edec79cb35e..d116e98ccfc 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/NestedLoggerConfigTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/NestedLoggerConfigTest.java @@ -16,18 +16,15 @@ */ package org.apache.logging.log4j.core.config; -import com.google.common.collect.ImmutableList; +import java.io.IOException; +import java.util.List; + import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.xml.XmlConfiguration; +import org.apache.logging.log4j.core.test.junit.LoggingTestContext; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - import static org.junit.Assert.assertEquals; /** @@ -38,7 +35,7 @@ public class NestedLoggerConfigTest { @Parameterized.Parameters(name = "{0}") public static List data() throws IOException { - return ImmutableList.of("logger-config/LoggerConfig/", "logger-config/AsyncLoggerConfig/"); + return List.of("logger-config/LoggerConfig/", "logger-config/AsyncLoggerConfig/"); } private final String prefix; @@ -48,31 +45,34 @@ public NestedLoggerConfigTest(String prefix) { } @Test - public void testInheritParentDefaultLevel() throws IOException { - Configuration configuration = loadConfiguration(prefix + "default-level.xml"); + public void testInheritParentDefaultLevel() { + final LoggingTestContext testContext = loadConfiguration(prefix + "default-level.xml"); + Configuration configuration = testContext.getLoggerContext().getConfiguration(); try { assertEquals(Level.ERROR, configuration.getLoggerConfig("com.foo").getLevel()); } finally { - configuration.stop(); + testContext.close(); } } @Test - public void testInheritParentLevel() throws IOException { - Configuration configuration = loadConfiguration(prefix + "inherit-level.xml"); + public void testInheritParentLevel() { + final LoggingTestContext testContext = loadConfiguration(prefix + "inherit-level.xml"); + Configuration configuration = testContext.getLoggerContext().getConfiguration(); try { assertEquals(Level.TRACE, configuration.getLoggerConfig("com.foo").getLevel()); } finally { - configuration.stop(); + testContext.close(); } } - private Configuration loadConfiguration(String resourcePath) throws IOException { - try (InputStream in = getClass().getClassLoader().getResourceAsStream(resourcePath)) { - Configuration configuration = new XmlConfiguration(new LoggerContext("test"), new ConfigurationSource(in)); - configuration.initialize(); - configuration.start(); - return configuration; - } + private LoggingTestContext loadConfiguration(String resourcePath) { + final LoggingTestContext testContext = LoggingTestContext.configurer() + .setContextName("test") + .setConfigurationLocation("classpath:" + resourcePath) + .setClassLoader(getClass().getClassLoader()) + .build(); + testContext.init(null); + return testContext; } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java index 59cf193cfc7..0f69325300f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java @@ -16,6 +16,15 @@ */ package org.apache.logging.log4j.core.config; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,23 +39,15 @@ import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; +import org.apache.logging.log4j.core.config.xml.XmlConfiguration; import org.apache.logging.log4j.core.filter.CompositeFilter; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.test.junit.StatusLoggerLevel; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.Serializable; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.concurrent.TimeUnit; - import static org.apache.logging.log4j.core.test.hamcrest.MapMatchers.hasSize; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -93,7 +94,9 @@ public void testInitialize_Name_PathName() throws Exception { ctx = Configurator.initialize("Test1", "target/test-classes/log4j2-config.xml"); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -109,7 +112,9 @@ public void testInitialize_Name_ClassLoader_URI() throws Exception { ctx = Configurator.initialize("Test1", null, new File("target/test-classes/log4j2-config.xml").toURI()); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -128,7 +133,9 @@ public void testInitialize_InputStream_File() throws Exception { ctx = Configurator.initialize(null, source); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -147,7 +154,9 @@ public void testInitialize_InputStream_Path() throws Exception { ctx = Configurator.initialize(null, source); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -166,7 +175,9 @@ public void testInitialize_NullClassLoader_ConfigurationSourceWithInputStream_No ctx = Configurator.initialize(null, source); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -182,7 +193,9 @@ public void testInitialize_Name_LocationName() throws Exception { ctx = Configurator.initialize("Test1", "log4j2-config.xml"); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -199,7 +212,9 @@ public void testFromClassPathProperty() throws Exception { ctx = Configurator.initialize("Test1", null); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -215,7 +230,9 @@ public void testFromClassPathWithClassPathPrefix() throws Exception { ctx = Configurator.initialize("Test1", "classpath:log4j2-config.xml"); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -231,7 +248,9 @@ public void testFromClassPathWithClassLoaderPrefix() throws Exception { ctx = Configurator.initialize("Test1", "classloader:log4j2-config.xml"); LogManager.getLogger("org.apache.test.TestConfigurator"); Configuration config = ctx.getConfiguration(); - assertNotNull(config, "No configuration"); + Assertions.assertThat(config) + .isNotNull() + .isInstanceOf(XmlConfiguration.class); assertEquals(CONFIG_NAME, config.getName(), "Incorrect Configuration."); final Map map = config.getAppenders(); assertNotNull(map, "Appenders map should not be null."); @@ -309,7 +328,7 @@ public void testEnvironment() throws Exception { assertThat(map, hasSize(greaterThan(0))); assertThat("No ListAppender named List2", map, hasKey("List2")); final Appender app = map.get("List2"); - final Layout layout = app.getLayout(); + final Layout layout = app.getLayout(); assertNotNull(layout, "Appender List2 does not have a Layout"); assertThat("Appender List2 is not configured with a PatternLayout", layout, instanceOf(PatternLayout.class)); final String pattern = ((PatternLayout) layout).getConversionPattern(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/arbiters/BasicArbiterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/arbiters/BasicArbiterTest.java index 2e808696e38..03f661b2973 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/arbiters/BasicArbiterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/arbiters/BasicArbiterTest.java @@ -23,6 +23,7 @@ import org.apache.logging.log4j.core.test.appender.ListAppender; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.SetSystemProperty; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -43,8 +44,8 @@ public void after() { } @Test + @SetSystemProperty(key = "env", value = "prod") public void prodTest() { - System.setProperty("env", "prod"); loggerContext = Configurator.initialize(null, CONFIG); assertNotNull(loggerContext); Appender app = loggerContext.getConfiguration().getAppender("Out"); @@ -53,8 +54,8 @@ public void prodTest() { } @Test + @SetSystemProperty(key = "env", value = "dev") public void devTest() { - System.setProperty("env", "dev"); loggerContext = Configurator.initialize(null, CONFIG); assertNotNull(loggerContext); Appender app = loggerContext.getConfiguration().getAppender("Out"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java index ecf9364bd2c..aea17d8f6cf 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilterTest.java @@ -16,20 +16,21 @@ */ package org.apache.logging.log4j.core.filter; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.test.junit.UsingThreadContextMap; import org.junit.jupiter.api.Test; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.*; @UsingThreadContextMap @@ -46,6 +47,8 @@ public void testFilter() { .setKey("userid") .setPairs(pairs) .setDefaultThreshold(Level.ERROR) + .setContextDataFactory(new DefaultContextDataFactory()) + .setContextDataInjector(new ThreadContextDataInjector.ForDefaultThreadContextMap()) .get(); filter.start(); assertTrue(filter.isStarted()); @@ -54,9 +57,9 @@ public void testFilter() { ThreadContext.clearMap(); ThreadContext.put("userid", "JohnDoe"); ThreadContext.put("organization", "apache"); - LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(new SimpleMessage("Test")).build(); + LogEvent event = LogEvent.builder().setLevel(Level.DEBUG).setMessage(new SimpleMessage("Test")).get(); assertSame(Filter.Result.DENY, filter.filter(event)); - event = Log4jLogEvent.newBuilder().setLevel(Level.ERROR).setMessage(new SimpleMessage("Test")).build(); + event = LogEvent.builder().setLevel(Level.ERROR).setMessage(new SimpleMessage("Test")).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); ThreadContext.clearMap(); } @@ -74,6 +77,8 @@ public void testFilterWorksWhenParamsArePassedAsArguments() { .setDefaultThreshold(Level.ERROR) .setOnMatch(Filter.Result.ACCEPT) .setOnMismatch(Filter.Result.NEUTRAL) + .setContextDataFactory(new DefaultContextDataFactory()) + .setContextDataInjector(new ThreadContextDataInjector.ForDefaultThreadContextMap()) .get(); filter.start(); assertTrue(filter.isStarted()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java index 712fe0a4eaf..76fcda6040a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java @@ -41,17 +41,12 @@ import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; /** * Unit test for simple App. @@ -112,16 +107,18 @@ public void after() { @Test public void filterTest() throws Exception { - System.setProperty("log4j2.Configuration.allowedProtocols", "http"); - System.setProperty("logging.auth.username", "log4j"); - System.setProperty("logging.auth.password", "log4j"); - System.setProperty("configLocation", "http://localhost:" + port + "/testConfig.json"); + String contextName = getClass().getSimpleName(); + String configLocation = "http://localhost:" + port + "/testConfig.json"; + System.setProperty("log4j2.HttpThreadContextMapFilterTest.Configuration.location", configLocation); + System.setProperty("log4j2.HttpThreadContextMapFilterTest.Configuration.allowedProtocols", "http"); + System.setProperty("log4j2.HttpThreadContextMapFilterTest.Configuration.TransportSecurity.basicUsername", "log4j"); + System.setProperty("log4j2.HttpThreadContextMapFilterTest.Configuration.TransportSecurity.basicPassword", "log4j"); ThreadContext.put("loginId", "rgoers"); Path source = new File("target/test-classes/emptyConfig.json").toPath(); Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); long fileTime = targetFile.lastModified() - 2000; assertTrue(targetFile.setLastModified(fileTime)); - loggerContext = Configurator.initialize(null, CONFIG); + loggerContext = Configurator.initialize(contextName, CONFIG); assertNotNull(loggerContext); Appender app = loggerContext.getConfiguration().getAppender("List"); assertNotNull(app); @@ -131,7 +128,7 @@ public void filterTest() throws Exception { filter.registerListener(this); Logger logger = loggerContext.getLogger("Test"); logger.debug("This is a test"); - Assertions.assertEquals(0, ((ListAppender) app).getEvents().size()); + assertEquals(0, ((ListAppender) app).getEvents().size()); source = new File("target/test-classes/filterConfig.json").toPath(); Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); assertNotEquals(fileTime, targetFile.lastModified()); @@ -140,8 +137,8 @@ public void filterTest() throws Exception { } updated = new CountDownLatch(1); logger.debug("This is a test"); - Assertions.assertEquals(1, ((ListAppender) app).getEvents().size()); - Assertions.assertTrue(Files.deleteIfExists(target)); + assertEquals(1, ((ListAppender) app).getEvents().size()); + assertTrue(Files.deleteIfExists(target)); if (!updated.await(5, TimeUnit.SECONDS)) { fail("File update for delete was not detected"); } @@ -161,7 +158,7 @@ protected void doGet(HttpServletRequest request, } while (headers.hasMoreElements()) { String authData = headers.nextElement(); - Assert.assertTrue("Not a Basic auth header", authData.startsWith(BASIC)); + assertTrue(authData.startsWith(BASIC), "Not a Basic auth header"); String credentials = new String(decoder.decode(authData.substring(BASIC.length()))); if (!expectedCreds.equals(credentials)) { response.sendError(401, "Invalid credentials"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java index 97d8140737d..89cce3f53c6 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java @@ -19,11 +19,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; public class LevelRangeFilterTest { @@ -34,15 +34,15 @@ public void testLevels() { assertTrue(filter.isStarted()); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null)); assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null)); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); assertSame(Filter.Result.DENY, filter.filter(event)); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLevel(Level.ERROR) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MarkerFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MarkerFilterTest.java index 8ef4a460d85..ef5ed7e2db2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MarkerFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MarkerFilterTest.java @@ -21,11 +21,11 @@ import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; public class MarkerFilterTest { @@ -43,18 +43,20 @@ public void testMarkers() { assertSame(Filter.Result.NEUTRAL, filter.filter(null, null, child, (Object) null, (Throwable) null)); assertSame(Filter.Result.NEUTRAL, filter.filter(null, null, grandChild, (Object) null, (Throwable) null)); filter.stop(); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setMarker(grandChild) // .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); filter = MarkerFilter.createFilter("Child", null, null); filter.start(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setMarker(sibling) // .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertSame(Filter.Result.DENY, filter.filter(event)); filter.stop(); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/NoMarkerFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/NoMarkerFilterTest.java index d98a5d4faa0..41a7bc4ecc5 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/NoMarkerFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/NoMarkerFilterTest.java @@ -21,11 +21,11 @@ import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; public class NoMarkerFilterTest { @@ -38,17 +38,19 @@ public void testMarkers() { assertSame(Filter.Result.DENY, filter.filter(null, null, sampleMarker, (Object) null, (Throwable) null)); assertSame(Filter.Result.NEUTRAL, filter.filter(null, null, null, (Object) null, (Throwable) null)); filter.stop(); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); filter.start(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setMarker(sampleMarker) // .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertSame(Filter.Result.DENY, filter.filter(event)); filter.stop(); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index 9b682632370..15375fd2ac6 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -20,7 +20,6 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Filter.Result; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.status.StatusLogger; @@ -46,15 +45,15 @@ public void testThresholds() throws Exception { filter.filter(null, Level.DEBUG, null, (Object) "This is a test message", (Throwable) null)); assertSame(Filter.Result.DENY, filter.filter(null, Level.ERROR, null, (Object) "This is not a test", (Throwable) null)); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Another test message")) // - .build(); + .get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLevel(Level.ERROR) // .setMessage(new SimpleMessage("test")) // - .build(); + .get(); assertSame(Filter.Result.DENY, filter.filter(event)); filter = RegexFilter.createFilter(null, null, false, null, null); assertNull(filter); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilterTest.java index 2ef851cb31f..c21b9f5533b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilterTest.java @@ -18,7 +18,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.impl.ContextDataFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.core.util.KeyValuePair; import org.junit.jupiter.api.Test; @@ -32,7 +36,14 @@ public void testFilter() { ThreadContext.put("organization", "Apache"); final KeyValuePair[] pairs = new KeyValuePair[] { new KeyValuePair("userid", "JohnDoe"), new KeyValuePair("organization", "Apache")}; - ThreadContextMapFilter filter = ThreadContextMapFilter.createFilter(pairs, "and", null, null); + ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + ContextDataInjector contextDataInjector = ThreadContextDataInjector.create(contextDataFactory); + ThreadContextMapFilter filter = ThreadContextMapFilter.newBuilder() + .setPairs(pairs) + .setOperator("and") + .setContextDataFactory(contextDataFactory) + .setContextDataInjector(contextDataInjector) + .get(); assertNotNull(filter); filter.start(); assertTrue(filter.isStarted()); @@ -44,7 +55,12 @@ public void testFilter() { ThreadContext.put("organization", "ASF"); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null)); ThreadContext.clearMap(); - filter = ThreadContextMapFilter.createFilter(pairs, "or", null, null); + filter = ThreadContextMapFilter.newBuilder() + .setPairs(pairs) + .setOperator("or") + .setContextDataFactory(contextDataFactory) + .setContextDataInjector(contextDataInjector) + .get(); assertNotNull(filter); filter.start(); assertTrue(filter.isStarted()); @@ -56,7 +72,11 @@ public void testFilter() { ThreadContext.remove("organization"); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null)); final KeyValuePair[] single = new KeyValuePair[] {new KeyValuePair("userid", "testuser")}; - filter = ThreadContextMapFilter.createFilter(single, null, null, null); + filter = ThreadContextMapFilter.newBuilder() + .setPairs(single) + .setContextDataFactory(contextDataFactory) + .setContextDataInjector(contextDataInjector) + .get(); assertNotNull(filter); filter.start(); assertTrue(filter.isStarted()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThresholdFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThresholdFilterTest.java index 4fed5118ac1..f50a9451ddc 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThresholdFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/ThresholdFilterTest.java @@ -19,11 +19,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ThresholdFilterTest { @@ -34,15 +34,15 @@ public void testThresholds() { assertTrue(filter.isStarted()); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null)); assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null)); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); assertSame(Filter.Result.DENY, filter.filter(event)); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLevel(Level.ERROR) // .setMessage(new SimpleMessage("Test")) // - .build(); + .get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event)); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java index 4c586557314..189c89dbf4c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java @@ -16,12 +16,6 @@ */ package org.apache.logging.log4j.core.filter; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.time.Clock; -import org.junit.jupiter.api.Test; - import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; @@ -29,6 +23,11 @@ import java.util.Calendar; import java.util.TimeZone; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.time.Clock; +import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -51,17 +50,17 @@ public void springForward() { assertTrue(filter.isStarted()); ZonedDateTime date = ZonedDateTime.of(2020, 3, 8, 2, 6, 30, 0, ZoneId.of("America/Los_Angeles")); CLOCKTIME = date.toInstant().toEpochMilli(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusDays(1).withHour(2); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.withHour(4); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); } @@ -75,22 +74,22 @@ public void fallBack() { assertTrue(filter.isStarted()); ZonedDateTime date = ZonedDateTime.of(2020, 11, 1, 1, 6, 30, 0, ZoneId.of("America/Los_Angeles")).withEarlierOffsetAtOverlap(); CLOCKTIME = date.toInstant().toEpochMilli(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = ZonedDateTime.of(2020, 11, 1, 1, 6, 30, 0, ZoneId.of("America/Los_Angeles")).withLaterOffsetAtOverlap(); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); date = date.plusDays(1).withHour(1).withMinute(30); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.withHour(4); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); } @@ -104,22 +103,22 @@ public void overnight() { assertTrue(filter.isStarted()); ZonedDateTime date = ZonedDateTime.of(2020, 3, 10, 23, 30, 30, 0, ZoneId.of("America/Los_Angeles")).withEarlierOffsetAtOverlap(); CLOCKTIME = date.toInstant().toEpochMilli(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(1); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(1); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); date = date.plusDays(1).withHour(0); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); } @@ -132,22 +131,22 @@ public void overnightForward() { assertTrue(filter.isStarted()); ZonedDateTime date = ZonedDateTime.of(2020, 3, 7, 23, 30, 30, 0, ZoneId.of("America/Los_Angeles")).withEarlierOffsetAtOverlap(); CLOCKTIME = date.toInstant().toEpochMilli(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(1); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(2); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); date = date.plusDays(1).withHour(0); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); } @@ -161,22 +160,22 @@ public void overnightFallback() { assertTrue(filter.isStarted()); ZonedDateTime date = ZonedDateTime.of(2020, 10, 31, 23, 30, 30, 0, ZoneId.of("America/Los_Angeles")).withEarlierOffsetAtOverlap(); CLOCKTIME = date.toInstant().toEpochMilli(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(1); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); date = date.plusHours(2); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); date = date.plusDays(1).withHour(0); CLOCKTIME = date.toInstant().toEpochMilli(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); } @@ -195,7 +194,7 @@ public void testTime() { final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles")); cal.set(Calendar.HOUR_OF_DAY, 2); CLOCKTIME = cal.getTimeInMillis(); - LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + LogEvent event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); //assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null)); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); @@ -203,14 +202,14 @@ public void testTime() { cal.add(Calendar.DATE, 1); cal.set(Calendar.HOUR_OF_DAY, 2); CLOCKTIME = cal.getTimeInMillis(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); assertSame(Filter.Result.NEUTRAL, filter.filter(event), "Time " + CLOCKTIME + " is not within range: " + filter.toString()); //assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null)); cal.set(Calendar.HOUR_OF_DAY, 4); CLOCKTIME = cal.getTimeInMillis(); - event = Log4jLogEvent.newBuilder().setTimeMillis(CLOCKTIME).build(); + event = LogEvent.builder().setTimeMillis(CLOCKTIME).get(); //assertSame(Filter.Result.DENY, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null)); assertSame(Filter.Result.DENY, filter.filter(event), "Time " + CLOCKTIME + " is within range: " + filter.toString()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetMissingConstructorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetMissingConstructorTest.java deleted file mode 100644 index e499c144b1e..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetMissingConstructorTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import org.apache.logging.log4j.util.SortedArrayStringMap; -import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.SetSystemProperty; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * Tests the ContextDataFactory class. - */ -@SetSystemProperty(key = Log4jProperties.THREAD_CONTEXT_DATA_CLASS_NAME, value = "org.apache.logging.log4j.core.impl.FactoryTestStringMapWithoutIntConstructor") -public class ContextDataFactoryPropertySetMissingConstructorTest { - - @Test - public void intArgReturnsSortedArrayStringMapIfPropertySpecifiedButMissingIntConstructor() throws Exception { - assertTrue(ContextDataFactory.createContextData(2) instanceof SortedArrayStringMap); - final SortedArrayStringMap actual = (SortedArrayStringMap) ContextDataFactory.createContextData(2); - assertEquals(2, actual.getThreshold()); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetTest.java deleted file mode 100644 index d706f30cf34..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryPropertySetTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.SetSystemProperty; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * Tests the ContextDataFactory class. - */ -@SetSystemProperty(key = Log4jProperties.THREAD_CONTEXT_DATA_CLASS_NAME, value = "org.apache.logging.log4j.core.impl.FactoryTestStringMap") -public class ContextDataFactoryPropertySetTest { - - @Test - public void noArgReturnsSpecifiedImplIfPropertySpecified() throws Exception { - assertTrue(ContextDataFactory.createContextData() instanceof FactoryTestStringMap); - } - - @Test - public void intArgReturnsSpecifiedImplIfPropertySpecified() throws Exception { - assertTrue(ContextDataFactory.createContextData(2) instanceof FactoryTestStringMap); - } - - @Test - public void intArgSetsCapacityIfPropertySpecified() throws Exception { - final FactoryTestStringMap actual = (FactoryTestStringMap) ContextDataFactory.createContextData(2); - assertEquals(2, actual.initialCapacity); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryTest.java index 8e94bb00d8c..498877059f4 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ContextDataFactoryTest.java @@ -19,25 +19,29 @@ import org.apache.logging.log4j.util.SortedArrayStringMap; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Tests the ContextDataFactory class. */ public class ContextDataFactoryTest { + private final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + @Test public void noArgReturnsSortedArrayStringMapIfNoPropertySpecified() throws Exception { - assertTrue(ContextDataFactory.createContextData() instanceof SortedArrayStringMap); + + assertTrue(contextDataFactory.createContextData() instanceof SortedArrayStringMap); } @Test public void intArgReturnsSortedArrayStringMapIfNoPropertySpecified() throws Exception { - assertTrue(ContextDataFactory.createContextData(2) instanceof SortedArrayStringMap); + assertTrue(contextDataFactory.createContextData(2) instanceof SortedArrayStringMap); } @Test public void intArgSetsCapacityIfNoPropertySpecified() throws Exception { - final SortedArrayStringMap actual = (SortedArrayStringMap) ContextDataFactory.createContextData(2); + final SortedArrayStringMap actual = (SortedArrayStringMap) contextDataFactory.createContextData(2); assertEquals(2, actual.getThreshold()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ImmutableLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ImmutableLogEventTest.java new file mode 100644 index 00000000000..da8e21831e9 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ImmutableLogEventTest.java @@ -0,0 +1,349 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.impl; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.test.util.FixedTimeClock; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.ObjectMessage; +import org.apache.logging.log4j.message.ReusableMessage; +import org.apache.logging.log4j.message.ReusableObjectMessage; +import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.SortedArrayStringMap; +import org.apache.logging.log4j.util.StringMap; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ImmutableLogEventTest { + + @Test + public void testToImmutableSame() { + final LogEvent logEvent = LogEvent.builder().get(); + assertSame(logEvent, logEvent.toImmutable()); + } + + @Test + public void testToImmutableNotSame() { + final LogEvent logEvent = LogEvent.builder().setMessage(new ReusableObjectMessage()).get(); + final LogEvent immutable = logEvent.toImmutable(); + assertSame(logEvent, immutable); + assertFalse(immutable.getMessage() instanceof ReusableMessage); + } + + @Test + public void testNullLevelReplacedWithOFF() { + final LogEvent evt = LogEvent.builder().setLevel(null).get(); + assertEquals(Level.OFF, evt.getLevel()); + } + + @Test + public void testTimestampGeneratedByClock() { + final LogEvent evt = LogEvent.builder().setClock(new FixedTimeClock()).get(); + assertEquals(FixedTimeClock.FIXED_TIME, evt.getTimeMillis()); + } + + @Test + public void testBuilderCorrectlyCopiesAllEventAttributes() { + final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + final StringMap contextData = contextDataFactory.createContextData(); + contextData.putValue("A", "B"); + final ContextStack contextStack = ThreadContext.getImmutableStack(); + final Exception exception = new Exception("test"); + final Marker marker = MarkerManager.getMarker("EVENTTEST"); + final Message message = new SimpleMessage("foo"); + final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); + final String fqcn = "qualified"; + final String name = "Ceci n'est pas une pipe"; + final String threadName = "threadName"; + final LogEvent event = LogEvent.builder() // + .setContextData(contextData) // + .setContextStack(contextStack) // + .endOfBatch(true) // + .includeLocation(true) // + .setLevel(Level.FATAL) // + .setLoggerFqcn(fqcn) // + .setLoggerName(name) // + .setMarker(marker) // + .setMessage(message) // + .setNanoTime(1234567890L) // + .setSource(stackTraceElement) // + .setThreadName(threadName) // + .setThrown(exception) // + .setTimeMillis(987654321L) + .get(); + + assertEquals(contextData, event.getContextData()); + assertSame(contextStack, event.getContextStack()); + assertTrue(event.isEndOfBatch()); + assertTrue(event.isIncludeLocation()); + assertSame(Level.FATAL, event.getLevel()); + assertSame(fqcn, event.getLoggerFqcn()); + assertSame(name, event.getLoggerName()); + assertSame(marker, event.getMarker()); + assertSame(message, event.getMessage()); + assertEquals(1234567890L, event.getNanoTime()); + assertSame(stackTraceElement, event.getSource()); + assertSame(threadName, event.getThreadName()); + assertSame(exception, event.getThrown()); + assertEquals(987654321L, event.getTimeMillis()); + + final LogEvent event2 = event.copy(); + assertEquals(event2, event, "copy constructor builder"); + assertNotSame(event2, event); + assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); + } + + @Test + public void testBuilderCorrectlyCopiesAllEventAttributesInclContextData() { + final StringMap contextData = new SortedArrayStringMap(); + contextData.putValue("A", "B"); + final ContextStack contextStack = ThreadContext.getImmutableStack(); + final Exception exception = new Exception("test"); + final Marker marker = MarkerManager.getMarker("EVENTTEST"); + final Message message = new SimpleMessage("foo"); + final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); + final String fqcn = "qualified"; + final String name = "Ceci n'est pas une pipe"; + final String threadName = "threadName"; + final LogEvent event = LogEvent.builder() // + .setContextData(contextData) // + .setContextStack(contextStack) // + .endOfBatch(true) // + .includeLocation(true) // + .setLevel(Level.FATAL) // + .setLoggerFqcn(fqcn) // + .setLoggerName(name) // + .setMarker(marker) // + .setMessage(message) // + .setNanoTime(1234567890L) // + .setSource(stackTraceElement) // + .setThreadName(threadName) // + .setThrown(exception) // + .setTimeMillis(987654321L) + .get(); + + assertSame(contextData, event.getContextData()); + assertSame(contextStack, event.getContextStack()); + assertTrue(event.isEndOfBatch()); + assertTrue(event.isIncludeLocation()); + assertSame(Level.FATAL, event.getLevel()); + assertSame(fqcn, event.getLoggerFqcn()); + assertSame(name, event.getLoggerName()); + assertSame(marker, event.getMarker()); + assertSame(message, event.getMessage()); + assertEquals(1234567890L, event.getNanoTime()); + assertSame(stackTraceElement, event.getSource()); + assertSame(threadName, event.getThreadName()); + assertSame(exception, event.getThrown()); + assertEquals(987654321L, event.getTimeMillis()); + + final LogEvent event2 = event.copy(); + assertEquals(event2, event, "copy constructor builder"); + assertNotSame(event2, event); + assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); + } + + @Test + public void testBuilderCorrectlyCopiesMutableLogEvent() { + final StringMap contextData = new SortedArrayStringMap(); + contextData.putValue("A", "B"); + final ContextStack contextStack = ThreadContext.getImmutableStack(); + final Exception exception = new Exception("test"); + final Marker marker = MarkerManager.getMarker("EVENTTEST"); + final Message message = new SimpleMessage("foo"); + new StackTraceElement("A", "B", "file", 123); + final String fqcn = "qualified"; + final String name = "Ceci n'est pas une pipe"; + final String threadName = "threadName"; + final MutableLogEvent event = new MutableLogEvent(); + event.setContextData(contextData); + event.setContextStack(contextStack); + event.setEndOfBatch(true); + event.setIncludeLocation(true); + //event.setSource(stackTraceElement); // cannot be explicitly set + event.setLevel(Level.FATAL); + event.setLoggerFqcn(fqcn); + event.setLoggerName(name); + event.setMarker(marker); + event.setMessage(message); + event.setNanoTime(1234567890L); + event.setThreadName(threadName); + event.setThrown(exception); + event.setTimeMillis(987654321L); + + assertSame(contextData, event.getContextData()); + assertSame(contextStack, event.getContextStack()); + assertTrue(event.isEndOfBatch()); + assertTrue(event.isIncludeLocation()); + assertSame(Level.FATAL, event.getLevel()); + assertSame(fqcn, event.getLoggerFqcn()); + assertSame(name, event.getLoggerName()); + assertSame(marker, event.getMarker()); + assertSame(message, event.getMessage()); + assertEquals(1234567890L, event.getNanoTime()); + //assertSame(stackTraceElement, event.getSource()); // don't invoke + assertSame(threadName, event.getThreadName()); + assertSame(exception, event.getThrown()); + assertEquals(987654321L, event.getTimeMillis()); + + final LogEvent e2 = event.copy(); + assertEquals(contextData, e2.getContextData()); + assertSame(contextStack, e2.getContextStack()); + assertTrue(e2.isEndOfBatch()); + assertTrue(e2.isIncludeLocation()); + assertSame(Level.FATAL, e2.getLevel()); + assertSame(fqcn, e2.getLoggerFqcn()); + assertSame(name, e2.getLoggerName()); + assertSame(marker, e2.getMarker()); + assertSame(message, e2.getMessage()); + assertEquals(1234567890L, e2.getNanoTime()); + //assertSame(stackTraceElement, e2.getSource()); // don't invoke + assertSame(threadName, e2.getThreadName()); + assertSame(exception, e2.getThrown()); + assertEquals(987654321L, e2.getTimeMillis()); + final StackTraceElement value = assertInstanceOf(ImmutableLogEvent.class, e2).getSourceOrNull(); + assertNull(value, "source in copy"); + } + + @Test + public void testEquals() { + final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + final StringMap contextData = contextDataFactory.createContextData(); + contextData.putValue("A", "B"); + ThreadContext.push("first"); + final ContextStack contextStack = ThreadContext.getImmutableStack(); + final Exception exception = new Exception("test"); + final Marker marker = MarkerManager.getMarker("EVENTTEST"); + final Message message = new SimpleMessage("foo"); + final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); + final String fqcn = "qualified"; + final String name = "Ceci n'est pas une pipe"; + final String threadName = "threadName"; + final LogEvent event = LogEvent.builder() // + .setContextData(contextData) // + .setContextStack(contextStack) // + .endOfBatch(true) // + .includeLocation(true) // + .setLevel(Level.FATAL) // + .setLoggerFqcn(fqcn) // + .setLoggerName(name) // + .setMarker(marker) // + .setMessage(message) // + .setNanoTime(1234567890L) // + .setSource(stackTraceElement) // + .setThreadName(threadName) // + .setThrown(exception) // + .setTimeMillis(987654321L) + .get(); + + assertEquals(contextData, event.getContextData()); + assertSame(contextStack, event.getContextStack()); + assertTrue(event.isEndOfBatch()); + assertTrue(event.isIncludeLocation()); + assertSame(Level.FATAL, event.getLevel()); + assertSame(fqcn, event.getLoggerFqcn()); + assertSame(name, event.getLoggerName()); + assertSame(marker, event.getMarker()); + assertSame(message, event.getMessage()); + assertEquals(1234567890L, event.getNanoTime()); + assertSame(stackTraceElement, event.getSource()); + assertSame(threadName, event.getThreadName()); + assertSame(exception, event.getThrown()); + assertEquals(987654321L, event.getTimeMillis()); + + final LogEvent event2 = builder(event).get(); + assertEquals(event2, event, "copy constructor builder"); + assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); + + assertEquals(contextData, event2.getContextData()); + assertSame(contextStack, event2.getContextStack()); + assertTrue(event2.isEndOfBatch()); + assertTrue(event2.isIncludeLocation()); + assertSame(Level.FATAL, event2.getLevel()); + assertSame(fqcn, event2.getLoggerFqcn()); + assertSame(name, event2.getLoggerName()); + assertSame(marker, event2.getMarker()); + assertSame(message, event2.getMessage()); + assertEquals(1234567890L, event2.getNanoTime()); + assertSame(stackTraceElement, event2.getSource()); + assertSame(threadName, event2.getThreadName()); + assertSame(exception, event2.getThrown()); + assertEquals(987654321L, event2.getTimeMillis()); + + final StringMap differentMap = contextDataFactory.emptyFrozenContextData(); + different("different contextMap", builder(event).setContextData(differentMap), event); + different("null contextMap", builder(event).setContextData((StringMap) null), event); + + ThreadContext.push("abc"); + final ContextStack contextStack2 = ThreadContext.getImmutableStack(); + different("different contextStack", builder(event).setContextStack(contextStack2), event); + different("null contextStack", builder(event).setContextStack(null), event); + + different("different EndOfBatch", builder(event).endOfBatch(false), event); + different("different IncludeLocation", builder(event).includeLocation(false), event); + + different("different level", builder(event).setLevel(Level.INFO), event); + different("null level", builder(event).setLevel(null), event); + + different("different fqcn", builder(event).setLoggerFqcn("different"), event); + different("null fqcn", builder(event).setLoggerFqcn(null), event); + + different("different name", builder(event).setLoggerName("different"), event); + assertThrows(NullPointerException.class, () -> different("null name", builder(event).setLoggerName(null), event)); + + different("different marker", builder(event).setMarker(MarkerManager.getMarker("different")), event); + different("null marker", builder(event).setMarker(null), event); + + different("different message", builder(event).setMessage(new ObjectMessage("different")), event); + assertThrows(NullPointerException.class, () -> different("null message", builder(event).setMessage(null), event)); + + different("different nanoTime", builder(event).setNanoTime(135), event); + different("different milliTime", builder(event).setTimeMillis(137), event); + + final StackTraceElement stack2 = new StackTraceElement("XXX", "YYY", "file", 123); + different("different source", builder(event).setSource(stack2), event); + different("null source", builder(event).setSource(null), event); + + different("different threadname", builder(event).setThreadName("different"), event); + different("null threadname", builder(event).setThreadName(null), event); + + different("different exception", builder(event).setThrown(new Error("Boo!")), event); + different("null exception", builder(event).setThrown(null), event); + } + + private static LogEventBuilder builder(final LogEvent event) { + return LogEvent.builderFrom(event); + } + + private void different(final String reason, final LogEventBuilder builder, final LogEvent event) { + final LogEvent other = builder.get(); + assertNotEquals(other, event, reason); + assertNotEquals(other.hashCode(), event.hashCode(), reason + " hashCode"); + } + + @Test + public void testToString() { + // Throws an NPE in 2.6.2 + assertNotNull(LogEvent.builder().get().toString()); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jContextFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jContextFactoryTest.java deleted file mode 100644 index 2d64c58e856..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jContextFactoryTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.apache.logging.log4j.core.selector.BasicContextSelector; -import org.apache.logging.log4j.plugins.di.DI; -import org.apache.logging.log4j.plugins.di.Injector; -import org.junit.jupiter.api.Test; - -public class Log4jContextFactoryTest { - - /** - * Tests whether the constructor parameters take priority over the default - * injector bindings. - */ - @Test - public void testParameterPriority() { - final Injector injector = DI.createInjector(); - injector.init(); - Log4jContextFactory factory = new Log4jContextFactory(new BasicContextSelector(injector)); - assertEquals(BasicContextSelector.class, factory.getSelector().getClass()); - factory = new Log4jContextFactory(factory); - assertEquals(Log4jContextFactory.class, factory.getShutdownCallbackRegistry().getClass()); - factory = new Log4jContextFactory(new BasicContextSelector(injector), factory); - assertEquals(BasicContextSelector.class, factory.getSelector().getClass()); - assertEquals(Log4jContextFactory.class, factory.getShutdownCallbackRegistry().getClass()); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java deleted file mode 100644 index 54431b63e01..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.MarkerManager; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.test.util.FixedTimeClock; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.message.ObjectMessage; -import org.apache.logging.log4j.message.ReusableMessage; -import org.apache.logging.log4j.message.ReusableObjectMessage; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.util.FilteredObjectInputStream; -import org.apache.logging.log4j.util.SortedArrayStringMap; -import org.apache.logging.log4j.util.StringMap; -import org.apache.logging.log4j.util.Strings; -import org.junit.jupiter.api.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.Field; -import java.util.Base64; - -import static org.junit.jupiter.api.Assertions.*; - -public class Log4jLogEventTest { - - private static final Base64.Decoder decoder = Base64.getDecoder(); - - @Test - public void testToImmutableSame() { - final LogEvent logEvent = Log4jLogEvent.newBuilder().build(); - assertSame(logEvent, logEvent.toImmutable()); - } - - @Test - public void testToImmutableNotSame() { - final LogEvent logEvent = new Log4jLogEvent.Builder().setMessage(new ReusableObjectMessage()).build(); - final LogEvent immutable = logEvent.toImmutable(); - assertSame(logEvent, immutable); - assertFalse(immutable.getMessage() instanceof ReusableMessage); - } - - @Test - public void testJavaIoSerializable() throws Exception { - final Log4jLogEvent evt = Log4jLogEvent.newBuilder() // - .setLoggerName("some.test") // - .setLoggerFqcn(Strings.EMPTY) // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("abc")) // - .build(); - - final byte[] binary = serialize(evt); - final Log4jLogEvent evt2 = deserialize(binary); - - assertEquals(evt.getTimeMillis(), evt2.getTimeMillis()); - assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn()); - assertEquals(evt.getLevel(), evt2.getLevel()); - assertEquals(evt.getLoggerName(), evt2.getLoggerName()); - assertEquals(evt.getMarker(), evt2.getMarker()); - assertEquals(evt.getContextData(), evt2.getContextData()); - assertEquals(evt.getContextStack(), evt2.getContextStack()); - assertEquals(evt.getMessage(), evt2.getMessage()); - assertEquals(evt.getSource(), evt2.getSource()); - assertEquals(evt.getThreadName(), evt2.getThreadName()); - assertEquals(evt.getThrown(), evt2.getThrown()); - assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch()); - assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation()); - } - - @Test - public void testJavaIoSerializableWithThrown() throws Exception { - final Error thrown = new InternalError("test error"); - final Log4jLogEvent evt = Log4jLogEvent.newBuilder() // - .setLoggerName("some.test") // - .setLoggerFqcn(Strings.EMPTY) // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("abc")) // - .setThrown(thrown) // - .build(); - - final byte[] binary = serialize(evt); - final Log4jLogEvent evt2 = deserialize(binary); - - assertEquals(evt.getTimeMillis(), evt2.getTimeMillis()); - assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn()); - assertEquals(evt.getLevel(), evt2.getLevel()); - assertEquals(evt.getLoggerName(), evt2.getLoggerName()); - assertEquals(evt.getMarker(), evt2.getMarker()); - assertEquals(evt.getContextData(), evt2.getContextData()); - assertEquals(evt.getContextStack(), evt2.getContextStack()); - assertEquals(evt.getMessage(), evt2.getMessage()); - assertEquals(evt.getSource(), evt2.getSource()); - assertEquals(evt.getThreadName(), evt2.getThreadName()); - assertNull(evt2.getThrown()); - assertNotNull(evt2.getThrownProxy()); - assertEquals(evt.getThrownProxy(), evt2.getThrownProxy()); - assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch()); - assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation()); - } - - private byte[] serialize(final Log4jLogEvent event) throws IOException { - final ByteArrayOutputStream arr = new ByteArrayOutputStream(); - final ObjectOutputStream out = new ObjectOutputStream(arr); - out.writeObject(event); - return arr.toByteArray(); - } - - @SuppressWarnings("BanSerializableRead") - private Log4jLogEvent deserialize(final byte[] binary) throws IOException, ClassNotFoundException { - final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new FilteredObjectInputStream(inArr); - final Log4jLogEvent result = (Log4jLogEvent) in.readObject(); - return result; - } - - // DO NOT REMOVE THIS COMMENT: - // UNCOMMENT WHEN GENERATING SERIALIZED EVENT FOR #testJavaIoSerializableWithUnknownThrowable - // public static class DeletedException extends Exception { - // private static final long serialVersionUID = 1L; - // public DeletedException(String msg) { - // super(msg); - // } - // }; - - @Test - public void testJavaIoSerializableWithUnknownThrowable() throws Exception { - final String loggerName = "some.test"; - final Marker marker = null; - final String loggerFQN = Strings.EMPTY; - final Level level = Level.INFO; - final Message msg = new SimpleMessage("abc"); - final String threadName = Thread.currentThread().getName(); - final String errorMessage = "OMG I've been deleted!"; - - // DO NOT DELETE THIS COMMENT: - // UNCOMMENT TO RE-GENERATE SERIALIZED EVENT WHEN UPDATING THIS TEST. - // final Exception thrown = new DeletedException(errorMessage); - // final Log4jLogEvent evt = new Log4jLogEvent(loggerName, marker, loggerFQN, level, msg, thrown); - // final byte[] binary = serialize(evt); - // String base64Str = DatatypeConverter.printBase64Binary(binary); - // System.out.println("final String base64 = \"" + base64Str.replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") + - // "\";"); - - final String base64 = "rO0ABXNyAD5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnQkTG9nRXZlbnRQcm94eYgtmn+yXsP9AwAQWgAMaXNFbmRPZkJhdGNoWgASaXNMb2NhdGlvblJlcXVpcmVkSgAIdGhyZWFkSWRJAA50aHJlYWRQcmlvcml0eUoACnRpbWVNaWxsaXNMAAtjb250ZXh0RGF0YXQAKUxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovdXRpbC9TdHJpbmdNYXA7TAAMY29udGV4dFN0YWNrdAA1TG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9UaHJlYWRDb250ZXh0JENvbnRleHRTdGFjaztMAAVsZXZlbHQAIExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovTGV2ZWw7TAAKbG9nZ2VyRlFDTnQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACmxvZ2dlck5hbWVxAH4ABEwABm1hcmtlcnQAIUxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovTWFya2VyO0wAEW1hcnNoYWxsZWRNZXNzYWdldAAbTGphdmEvcm1pL01hcnNoYWxsZWRPYmplY3Q7TAANbWVzc2FnZVN0cmluZ3EAfgAETAAGc291cmNldAAdTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMAAp0aHJlYWROYW1lcQB+AARMAAt0aHJvd25Qcm94eXQAM0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL1Rocm93YWJsZVByb3h5O3hwAAAAAAAAAAAAAQAAAAUAAAAASZYC0nNyADJvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGoudXRpbC5Tb3J0ZWRBcnJheVN0cmluZ01hcLA3yJFz7CvcAwACWgAJaW1tdXRhYmxlSQAJdGhyZXNob2xkeHABAAAAAXcIAAAAAQAAAAB4c3IAPm9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5UaHJlYWRDb250ZXh0JEVtcHR5VGhyZWFkQ29udGV4dFN0YWNrAAAAAAAAAAECAAB4cHNyAB5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouTGV2ZWwAAAAAABggGgIAA0kACGludExldmVsTAAEbmFtZXEAfgAETAANc3RhbmRhcmRMZXZlbHQALExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovc3BpL1N0YW5kYXJkTGV2ZWw7eHAAAAGQdAAESU5GT35yACpvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouc3BpLlN0YW5kYXJkTGV2ZWwAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AARJTkZPdAAAdAAJc29tZS50ZXN0cHNyABlqYXZhLnJtaS5NYXJzaGFsbGVkT2JqZWN0fL0el+1j/D4CAANJAARoYXNoWwAIbG9jQnl0ZXN0AAJbQlsACG9iakJ5dGVzcQB+ABl4cJNvO+xwdXIAAltCrPMX+AYIVOACAAB4cAAAAGms7QAFc3IALm9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5tZXNzYWdlLlNpbXBsZU1lc3NhZ2WLdE0wYLeiqAMAAUwAB21lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAA2FiY3h0AANhYmNwdAAEbWFpbnNyADFvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLlRocm93YWJsZVByb3h52cww1Zp7rPoCAAdJABJjb21tb25FbGVtZW50Q291bnRMAApjYXVzZVByb3h5cQB+AAhbABJleHRlbmRlZFN0YWNrVHJhY2V0AD9bTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvRXh0ZW5kZWRTdGFja1RyYWNlRWxlbWVudDtMABBsb2NhbGl6ZWRNZXNzYWdlcQB+AARMAAdtZXNzYWdlcQB+AARMAARuYW1lcQB+AARbABFzdXBwcmVzc2VkUHJveGllc3QANFtMb3JnL2FwYWNoZS9sb2dnaW5nL2xvZzRqL2NvcmUvaW1wbC9UaHJvd2FibGVQcm94eTt4cAAAAABwdXIAP1tMb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5FeHRlbmRlZFN0YWNrVHJhY2VFbGVtZW50O8rPiCOlx8+8AgAAeHAAAAAec3IAPG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuRXh0ZW5kZWRTdGFja1RyYWNlRWxlbWVudOHez7rGtpAHAgACTAAOZXh0cmFDbGFzc0luZm90ADZMb3JnL2FwYWNoZS9sb2dnaW5nL2xvZzRqL2NvcmUvaW1wbC9FeHRlbmRlZENsYXNzSW5mbztMABFzdGFja1RyYWNlRWxlbWVudHEAfgAHeHBzcgA0b3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5FeHRlbmRlZENsYXNzSW5mbwAAAAAAAAABAgADWgAFZXhhY3RMAAhsb2NhdGlvbnEAfgAETAAHdmVyc2lvbnEAfgAEeHABdAANdGVzdC1jbGFzc2VzL3QAAT9zcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50YQnFmiY23YUCAARJAApsaW5lTnVtYmVyTAAOZGVjbGFyaW5nQ2xhc3NxAH4ABEwACGZpbGVOYW1lcQB+AARMAAptZXRob2ROYW1lcQB+AAR4cAAAAKx0ADRvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnRUZXN0dAAWTG9nNGpMb2dFdmVudFRlc3QuamF2YXQAKnRlc3RKYXZhSW9TZXJpYWxpemFibGVXaXRoVW5rbm93blRocm93YWJsZXNxAH4AJXNxAH4AKABxAH4AK3QACDEuNy4wXzU1c3EAfgAs/////nQAJHN1bi5yZWZsZWN0Lk5hdGl2ZU1ldGhvZEFjY2Vzc29ySW1wbHQAHU5hdGl2ZU1ldGhvZEFjY2Vzc29ySW1wbC5qYXZhdAAHaW52b2tlMHNxAH4AJXNxAH4AKABxAH4AK3EAfgAzc3EAfgAsAAAAOXEAfgA1cQB+ADZ0AAZpbnZva2VzcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALAAAACt0AChzdW4ucmVmbGVjdC5EZWxlZ2F0aW5nTWV0aG9kQWNjZXNzb3JJbXBsdAAhRGVsZWdhdGluZ01ldGhvZEFjY2Vzc29ySW1wbC5qYXZhcQB+ADtzcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALAAAAl50ABhqYXZhLmxhbmcucmVmbGVjdC5NZXRob2R0AAtNZXRob2QuamF2YXEAfgA7c3EAfgAlc3EAfgAoAXQADmp1bml0LTQuMTIuamFydAAENC4xMnNxAH4ALAAAADJ0AClvcmcuanVuaXQucnVubmVycy5tb2RlbC5GcmFtZXdvcmtNZXRob2QkMXQAFEZyYW1ld29ya01ldGhvZC5qYXZhdAARcnVuUmVmbGVjdGl2ZUNhbGxzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAAAx0ADNvcmcuanVuaXQuaW50ZXJuYWwucnVubmVycy5tb2RlbC5SZWZsZWN0aXZlQ2FsbGFibGV0ABdSZWZsZWN0aXZlQ2FsbGFibGUuamF2YXQAA3J1bnNxAH4AJXNxAH4AKAF0AA5qdW5pdC00LjEyLmphcnEAfgBJc3EAfgAsAAAAL3QAJ29yZy5qdW5pdC5ydW5uZXJzLm1vZGVsLkZyYW1ld29ya01ldGhvZHEAfgBMdAARaW52b2tlRXhwbG9zaXZlbHlzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAABF0ADJvcmcuanVuaXQuaW50ZXJuYWwucnVubmVycy5zdGF0ZW1lbnRzLkludm9rZU1ldGhvZHQAEUludm9rZU1ldGhvZC5qYXZhdAAIZXZhbHVhdGVzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAAUV0AB5vcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXJ0ABFQYXJlbnRSdW5uZXIuamF2YXQAB3J1bkxlYWZzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAAE50AChvcmcuanVuaXQucnVubmVycy5CbG9ja0pVbml0NENsYXNzUnVubmVydAAbQmxvY2tKVW5pdDRDbGFzc1J1bm5lci5qYXZhdAAIcnVuQ2hpbGRzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAADlxAH4AbXEAfgBucQB+AG9zcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAASJ0ACBvcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXIkM3EAfgBncQB+AFRzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAAEd0ACBvcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXIkMXEAfgBndAAIc2NoZWR1bGVzcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAASBxAH4AZnEAfgBndAALcnVuQ2hpbGRyZW5zcQB+ACVzcQB+ACgBdAAOanVuaXQtNC4xMi5qYXJxAH4ASXNxAH4ALAAAADpxAH4AZnEAfgBndAAKYWNjZXNzJDAwMHNxAH4AJXNxAH4AKAF0AA5qdW5pdC00LjEyLmphcnEAfgBJc3EAfgAsAAABDHQAIG9yZy5qdW5pdC5ydW5uZXJzLlBhcmVudFJ1bm5lciQycQB+AGdxAH4AYXNxAH4AJXNxAH4AKAF0AA5qdW5pdC00LjEyLmphcnEAfgBJc3EAfgAsAAAAGnQAMG9yZy5qdW5pdC5pbnRlcm5hbC5ydW5uZXJzLnN0YXRlbWVudHMuUnVuQmVmb3Jlc3QAD1J1bkJlZm9yZXMuamF2YXEAfgBhc3EAfgAlc3EAfgAoAXQADmp1bml0LTQuMTIuamFycQB+AElzcQB+ACwAAAAbdAAvb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMuc3RhdGVtZW50cy5SdW5BZnRlcnN0AA5SdW5BZnRlcnMuamF2YXEAfgBhc3EAfgAlc3EAfgAoAXQADmp1bml0LTQuMTIuamFycQB+AElzcQB+ACwAAAFrcQB+AGZxAH4AZ3EAfgBUc3EAfgAlc3EAfgAoAXQADmp1bml0LTQuMTIuamFycQB+AElzcQB+ACwAAACJdAAab3JnLmp1bml0LnJ1bm5lci5KVW5pdENvcmV0AA5KVW5pdENvcmUuamF2YXEAfgBUc3EAfgAlc3EAfgAoAXQADGp1bml0LXJ0LmphcnEAfgArc3EAfgAsAAAAdXQAKGNvbS5pbnRlbGxpai5qdW5pdDQuSlVuaXQ0SWRlYVRlc3RSdW5uZXJ0ABlKVW5pdDRJZGVhVGVzdFJ1bm5lci5qYXZhdAATc3RhcnRSdW5uZXJXaXRoQXJnc3NxAH4AJXNxAH4AKAF0AAxqdW5pdC1ydC5qYXJxAH4AK3NxAH4ALAAAACpxAH4AqHEAfgCpcQB+AKpzcQB+ACVzcQB+ACgBdAAManVuaXQtcnQuamFycQB+ACtzcQB+ACwAAAEGdAAsY29tLmludGVsbGlqLnJ0LmV4ZWN1dGlvbi5qdW5pdC5KVW5pdFN0YXJ0ZXJ0ABFKVW5pdFN0YXJ0ZXIuamF2YXQAFnByZXBhcmVTdHJlYW1zQW5kU3RhcnRzcQB+ACVzcQB+ACgBdAAManVuaXQtcnQuamFycQB+ACtzcQB+ACwAAABUcQB+ALNxAH4AtHQABG1haW5zcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALP////5xAH4ANXEAfgA2cQB+ADdzcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALAAAADlxAH4ANXEAfgA2cQB+ADtzcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALAAAACtxAH4AP3EAfgBAcQB+ADtzcQB+ACVzcQB+ACgAcQB+ACtxAH4AM3NxAH4ALAAAAl5xAH4ARHEAfgBFcQB+ADtzcQB+ACVzcQB+ACgBdAALaWRlYV9ydC5qYXJxAH4AK3NxAH4ALAAAAJN0AC1jb20uaW50ZWxsaWoucnQuZXhlY3V0aW9uLmFwcGxpY2F0aW9uLkFwcE1haW50AAxBcHBNYWluLmphdmFxAH4AunQAFk9NRyBJJ3ZlIGJlZW4gZGVsZXRlZCFxAH4AzXQARW9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuTG9nNGpMb2dFdmVudFRlc3QkRGVsZXRlZEV4Y2VwdGlvbnVyADRbTG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuVGhyb3dhYmxlUHJveHk7+u0B4IWi6zkCAAB4cAAAAAB4"; - - final byte[] binaryDecoded = decoder.decode(base64); - final Log4jLogEvent evt2 = deserialize(binaryDecoded); - - assertEquals(loggerFQN, evt2.getLoggerFqcn()); - assertEquals(level, evt2.getLevel()); - assertEquals(loggerName, evt2.getLoggerName()); - assertEquals(marker, evt2.getMarker()); - assertEquals(msg, evt2.getMessage()); - assertEquals(threadName, evt2.getThreadName()); - assertNull(evt2.getThrown()); - assertEquals(this.getClass().getName() + "$DeletedException", evt2.getThrownProxy().getName()); - assertEquals(errorMessage, evt2.getThrownProxy().getMessage()); - } - - @Test - public void testNullLevelReplacedWithOFF() throws Exception { - final Level NULL_LEVEL = null; - final Log4jLogEvent evt = Log4jLogEvent.newBuilder().setLevel(NULL_LEVEL).build(); - assertEquals(Level.OFF, evt.getLevel()); - } - - @Test - public void testTimestampGeneratedByClock() { - final LogEvent evt = Log4jLogEvent.newBuilder().setClock(new FixedTimeClock()).build(); - assertEquals(FixedTimeClock.FIXED_TIME, evt.getTimeMillis()); - } - - @Test - public void testBuilderCorrectlyCopiesAllEventAttributes() { - final StringMap contextData = ContextDataFactory.createContextData(); - contextData.putValue("A", "B"); - final ContextStack contextStack = ThreadContext.getImmutableStack(); - final Exception exception = new Exception("test"); - final Marker marker = MarkerManager.getMarker("EVENTTEST"); - final Message message = new SimpleMessage("foo"); - final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); - final String fqcn = "qualified"; - final String name = "Ceci n'est pas une pipe"; - final String threadName = "threadName"; - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // - .setContextData(contextData) // - .setContextStack(contextStack) // - .setEndOfBatch(true) // - .setIncludeLocation(true) // - .setLevel(Level.FATAL) // - .setLoggerFqcn(fqcn) // - .setLoggerName(name) // - .setMarker(marker) // - .setMessage(message) // - .setNanoTime(1234567890L) // - .setSource(stackTraceElement) // - .setThreadName(threadName) // - .setThrown(exception) // - .setTimeMillis(987654321L) - .build(); - - assertEquals(contextData, event.getContextData()); - assertSame(contextStack, event.getContextStack()); - assertTrue(event.isEndOfBatch()); - assertTrue(event.isIncludeLocation()); - assertSame(Level.FATAL, event.getLevel()); - assertSame(fqcn, event.getLoggerFqcn()); - assertSame(name, event.getLoggerName()); - assertSame(marker, event.getMarker()); - assertSame(message, event.getMessage()); - assertEquals(1234567890L, event.getNanoTime()); - assertSame(stackTraceElement, event.getSource()); - assertSame(threadName, event.getThreadName()); - assertSame(exception, event.getThrown()); - assertEquals(987654321L, event.getTimeMillis()); - - final LogEvent event2 = new Log4jLogEvent.Builder(event).build(); - assertEquals(event2, event, "copy constructor builder"); - assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); - } - - @Test - public void testBuilderCorrectlyCopiesAllEventAttributesInclContextData() { - final StringMap contextData = new SortedArrayStringMap(); - contextData.putValue("A", "B"); - final ContextStack contextStack = ThreadContext.getImmutableStack(); - final Exception exception = new Exception("test"); - final Marker marker = MarkerManager.getMarker("EVENTTEST"); - final Message message = new SimpleMessage("foo"); - final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); - final String fqcn = "qualified"; - final String name = "Ceci n'est pas une pipe"; - final String threadName = "threadName"; - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // - .setContextData(contextData) // - .setContextStack(contextStack) // - .setEndOfBatch(true) // - .setIncludeLocation(true) // - .setLevel(Level.FATAL) // - .setLoggerFqcn(fqcn) // - .setLoggerName(name) // - .setMarker(marker) // - .setMessage(message) // - .setNanoTime(1234567890L) // - .setSource(stackTraceElement) // - .setThreadName(threadName) // - .setThrown(exception) // - .setTimeMillis(987654321L) - .build(); - - assertSame(contextData, event.getContextData()); - assertSame(contextStack, event.getContextStack()); - assertTrue(event.isEndOfBatch()); - assertTrue(event.isIncludeLocation()); - assertSame(Level.FATAL, event.getLevel()); - assertSame(fqcn, event.getLoggerFqcn()); - assertSame(name, event.getLoggerName()); - assertSame(marker, event.getMarker()); - assertSame(message, event.getMessage()); - assertEquals(1234567890L, event.getNanoTime()); - assertSame(stackTraceElement, event.getSource()); - assertSame(threadName, event.getThreadName()); - assertSame(exception, event.getThrown()); - assertEquals(987654321L, event.getTimeMillis()); - - final LogEvent event2 = new Log4jLogEvent.Builder(event).build(); - assertEquals(event2, event, "copy constructor builder"); - assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); - } - - @Test - public void testBuilderCorrectlyCopiesMutableLogEvent() throws Exception { - final StringMap contextData = new SortedArrayStringMap(); - contextData.putValue("A", "B"); - final ContextStack contextStack = ThreadContext.getImmutableStack(); - final Exception exception = new Exception("test"); - final Marker marker = MarkerManager.getMarker("EVENTTEST"); - final Message message = new SimpleMessage("foo"); - new StackTraceElement("A", "B", "file", 123); - final String fqcn = "qualified"; - final String name = "Ceci n'est pas une pipe"; - final String threadName = "threadName"; - final MutableLogEvent event = new MutableLogEvent(); - event.setContextData(contextData); - event.setContextStack(contextStack); - event.setEndOfBatch(true); - event.setIncludeLocation(true); - //event.setSource(stackTraceElement); // cannot be explicitly set - event.setLevel(Level.FATAL); - event.setLoggerFqcn(fqcn); - event.setLoggerName(name); - event.setMarker(marker); - event.setMessage(message); - event.setNanoTime(1234567890L); - event.setThreadName(threadName); - event.setThrown(exception); - event.setTimeMillis(987654321L); - - assertSame(contextData, event.getContextData()); - assertSame(contextStack, event.getContextStack()); - assertTrue(event.isEndOfBatch()); - assertTrue(event.isIncludeLocation()); - assertSame(Level.FATAL, event.getLevel()); - assertSame(fqcn, event.getLoggerFqcn()); - assertSame(name, event.getLoggerName()); - assertSame(marker, event.getMarker()); - assertSame(message, event.getMessage()); - assertEquals(1234567890L, event.getNanoTime()); - //assertSame(stackTraceElement, event.getSource()); // don't invoke - assertSame(threadName, event.getThreadName()); - assertSame(exception, event.getThrown()); - assertEquals(987654321L, event.getTimeMillis()); - - final LogEvent e2 = new Log4jLogEvent.Builder(event).build(); - assertEquals(contextData, e2.getContextData()); - assertSame(contextStack, e2.getContextStack()); - assertTrue(e2.isEndOfBatch()); - assertTrue(e2.isIncludeLocation()); - assertSame(Level.FATAL, e2.getLevel()); - assertSame(fqcn, e2.getLoggerFqcn()); - assertSame(name, e2.getLoggerName()); - assertSame(marker, e2.getMarker()); - assertSame(message, e2.getMessage()); - assertEquals(1234567890L, e2.getNanoTime()); - //assertSame(stackTraceElement, e2.getSource()); // don't invoke - assertSame(threadName, e2.getThreadName()); - assertSame(exception, e2.getThrown()); - assertEquals(987654321L, e2.getTimeMillis()); - - // use reflection to get value of source field in log event copy: - // invoking the getSource() method would initialize the field - final Field fieldSource = Log4jLogEvent.class.getDeclaredField("source"); - fieldSource.setAccessible(true); - final Object value = fieldSource.get(e2); - assertNull(value, "source in copy"); - } - - @Test - public void testEquals() { - final StringMap contextData = ContextDataFactory.createContextData(); - contextData.putValue("A", "B"); - ThreadContext.push("first"); - final ContextStack contextStack = ThreadContext.getImmutableStack(); - final Exception exception = new Exception("test"); - final Marker marker = MarkerManager.getMarker("EVENTTEST"); - final Message message = new SimpleMessage("foo"); - final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123); - final String fqcn = "qualified"; - final String name = "Ceci n'est pas une pipe"; - final String threadName = "threadName"; - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // - .setContextData(contextData) // - .setContextStack(contextStack) // - .setEndOfBatch(true) // - .setIncludeLocation(true) // - .setLevel(Level.FATAL) // - .setLoggerFqcn(fqcn) // - .setLoggerName(name) // - .setMarker(marker) // - .setMessage(message) // - .setNanoTime(1234567890L) // - .setSource(stackTraceElement) // - .setThreadName(threadName) // - .setThrown(exception) // - .setTimeMillis(987654321L) - .build(); - - assertEquals(contextData, event.getContextData()); - assertSame(contextStack, event.getContextStack()); - assertTrue(event.isEndOfBatch()); - assertTrue(event.isIncludeLocation()); - assertSame(Level.FATAL, event.getLevel()); - assertSame(fqcn, event.getLoggerFqcn()); - assertSame(name, event.getLoggerName()); - assertSame(marker, event.getMarker()); - assertSame(message, event.getMessage()); - assertEquals(1234567890L, event.getNanoTime()); - assertSame(stackTraceElement, event.getSource()); - assertSame(threadName, event.getThreadName()); - assertSame(exception, event.getThrown()); - assertEquals(987654321L, event.getTimeMillis()); - - final LogEvent event2 = builder(event).build(); - assertEquals(event2, event, "copy constructor builder"); - assertEquals(event2.hashCode(), event.hashCode(), "same hashCode"); - - assertEquals(contextData, event2.getContextData()); - assertSame(contextStack, event2.getContextStack()); - assertTrue(event2.isEndOfBatch()); - assertTrue(event2.isIncludeLocation()); - assertSame(Level.FATAL, event2.getLevel()); - assertSame(fqcn, event2.getLoggerFqcn()); - assertSame(name, event2.getLoggerName()); - assertSame(marker, event2.getMarker()); - assertSame(message, event2.getMessage()); - assertEquals(1234567890L, event2.getNanoTime()); - assertSame(stackTraceElement, event2.getSource()); - assertSame(threadName, event2.getThreadName()); - assertSame(exception, event2.getThrown()); - assertEquals(987654321L, event2.getTimeMillis()); - - final StringMap differentMap = ContextDataFactory.emptyFrozenContextData(); - different("different contextMap", builder(event).setContextData(differentMap), event); - different("null contextMap", builder(event).setContextData(null), event); - - ThreadContext.push("abc"); - final ContextStack contextStack2 = ThreadContext.getImmutableStack(); - different("different contextStack", builder(event).setContextStack(contextStack2), event); - different("null contextStack", builder(event).setContextStack(null), event); - - different("different EndOfBatch", builder(event).setEndOfBatch(false), event); - different("different IncludeLocation", builder(event).setIncludeLocation(false), event); - - different("different level", builder(event).setLevel(Level.INFO), event); - different("null level", builder(event).setLevel(null), event); - - different("different fqcn", builder(event).setLoggerFqcn("different"), event); - different("null fqcn", builder(event).setLoggerFqcn(null), event); - - different("different name", builder(event).setLoggerName("different"), event); - assertThrows(NullPointerException.class, () -> different("null name", builder(event).setLoggerName(null), event)); - - different("different marker", builder(event).setMarker(MarkerManager.getMarker("different")), event); - different("null marker", builder(event).setMarker(null), event); - - different("different message", builder(event).setMessage(new ObjectMessage("different")), event); - assertThrows(NullPointerException.class, () -> different("null message", builder(event).setMessage(null), event)); - - different("different nanoTime", builder(event).setNanoTime(135), event); - different("different milliTime", builder(event).setTimeMillis(137), event); - - final StackTraceElement stack2 = new StackTraceElement("XXX", "YYY", "file", 123); - different("different source", builder(event).setSource(stack2), event); - different("null source", builder(event).setSource(null), event); - - different("different threadname", builder(event).setThreadName("different"), event); - different("null threadname", builder(event).setThreadName(null), event); - - different("different exception", builder(event).setThrown(new Error("Boo!")), event); - different("null exception", builder(event).setThrown(null), event); - } - - private static Log4jLogEvent.Builder builder(final LogEvent event) { - return new Log4jLogEvent.Builder(event); - } - - private void different(final String reason, final Log4jLogEvent.Builder builder, final LogEvent event) { - final LogEvent other = builder.build(); - assertNotEquals(other, event, reason); - assertNotEquals(other.hashCode(), event.hashCode(), reason + " hashCode"); - } - - @Test - public void testToString() { - // Throws an NPE in 2.6.2 - assertNotNull(Log4jLogEvent.newBuilder().build().toString()); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java index d6639b15755..de02d5fa965 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java @@ -14,14 +14,8 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.impl; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.Arrays; import org.apache.logging.log4j.Level; @@ -33,11 +27,9 @@ import org.apache.logging.log4j.message.ReusableMessageFactory; import org.apache.logging.log4j.message.ReusableSimpleMessage; import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.util.FilteredObjectInputStream; +import org.apache.logging.log4j.spi.MutableThreadContextStack; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; -import org.apache.logging.log4j.spi.MutableThreadContextStack; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -49,8 +41,6 @@ public class MutableLogEventTest { private static final StringMap CONTEXT_DATA = createContextData(); private static final ThreadContext.ContextStack STACK = new MutableThreadContextStack(Arrays.asList("abc", "xyz")); - static boolean useObjectInputStream = false; - private static StringMap createContextData() { final StringMap result = new SortedArrayStringMap(); result.putValue("a", "1"); @@ -58,16 +48,6 @@ private static StringMap createContextData() { return result; } - @BeforeAll - public static void setupClass() { - try { - Class.forName("java.io.ObjectInputFilter"); - useObjectInputStream = true; - } catch (ClassNotFoundException ex) { - // Ignore the exception - } - } - @Test public void testToImmutable() { final LogEvent logEvent = new MutableLogEvent(); @@ -76,12 +56,11 @@ public void testToImmutable() { @Test public void testInitFromCopiesAllFields() { -// private ThrowableProxy thrownProxy; - final Log4jLogEvent source = Log4jLogEvent.newBuilder() // + final LogEvent source = LogEvent.builder() .setContextData(CONTEXT_DATA) // .setContextStack(STACK) // - .setEndOfBatch(true) // - .setIncludeLocation(true) // + .endOfBatch(true) // + .includeLocation(true) // .setLevel(Level.FATAL) // .setLoggerFqcn("a.b.c.d.e") // .setLoggerName("my name is Logger") // @@ -92,7 +71,7 @@ public void testInitFromCopiesAllFields() { .setThreadId(100).setThreadName("threadname").setThreadPriority(10) // .setThrown(new RuntimeException("run")) // .setTimeMillis(987654321) - .build(); + .get(); final MutableLogEvent mutable = new MutableLogEvent(); mutable.initFrom(source); assertEquals(CONTEXT_DATA, mutable.getContextData(), "contextMap"); @@ -117,11 +96,11 @@ public void testInitFromCopiesAllFields() { @Test public void testInitFromReusableCopiesFormatString() { Message message = ReusableMessageFactory.INSTANCE.newMessage("msg in a {}", "bottle"); - final Log4jLogEvent source = Log4jLogEvent.newBuilder() // + final LogEvent source = LogEvent.builder() // .setContextData(CONTEXT_DATA) // .setContextStack(STACK) // - .setEndOfBatch(true) // - .setIncludeLocation(true) // + .endOfBatch(true) // + .includeLocation(true) // .setLevel(Level.FATAL) // .setLoggerFqcn("a.b.c.d.e") // .setLoggerName("my name is Logger") // @@ -132,7 +111,7 @@ public void testInitFromReusableCopiesFormatString() { .setThreadId(100).setThreadName("threadname").setThreadPriority(10) // .setThrown(new RuntimeException("run")) // .setTimeMillis(987654321) - .build(); + .get(); final MutableLogEvent mutable = new MutableLogEvent(); mutable.initFrom(source); assertEquals("msg in a {}", mutable.getFormat(), "format"); @@ -143,12 +122,12 @@ public void testInitFromReusableCopiesFormatString() { assertEquals("msg in a bottle", memento.getFormattedMessage(), "formatted"); assertArrayEquals(new String[] {"bottle"}, memento.getParameters(), "parameters"); - Message eventMementoMessage = mutable.createMemento().getMessage(); + Message eventMementoMessage = mutable.copy().getMessage(); assertEquals("msg in a {}", eventMementoMessage.getFormat(), "format"); assertEquals("msg in a bottle", eventMementoMessage.getFormattedMessage(), "formatted"); assertArrayEquals(new String[] {"bottle"}, eventMementoMessage.getParameters(), "parameters"); - Message log4JLogEventMessage = new Log4jLogEvent.Builder(mutable).build().getMessage(); + Message log4JLogEventMessage = LogEvent.builderFrom(mutable).get().getMessage(); assertEquals("msg in a {}", log4JLogEventMessage.getFormat(), "format"); assertEquals("msg in a bottle", log4JLogEventMessage.getFormattedMessage(), "formatted"); assertArrayEquals(new String[] {"bottle"}, log4JLogEventMessage.getParameters(), "parameters"); @@ -158,11 +137,11 @@ public void testInitFromReusableCopiesFormatString() { public void testInitFromReusableObjectCopiesParameter() { Object param = new Object(); Message message = ReusableMessageFactory.INSTANCE.newMessage(param); - final Log4jLogEvent source = Log4jLogEvent.newBuilder() + final LogEvent source = LogEvent.builder() .setContextData(CONTEXT_DATA) .setContextStack(STACK) - .setEndOfBatch(true) - .setIncludeLocation(true) + .endOfBatch(true) + .includeLocation(true) .setLevel(Level.FATAL) .setLoggerFqcn("a.b.c.d.e") .setLoggerName("my name is Logger") @@ -174,7 +153,7 @@ public void testInitFromReusableObjectCopiesParameter() { .setThreadPriority(10) .setThrown(new RuntimeException("run")) .setTimeMillis(987654321) - .build(); + .get(); final MutableLogEvent mutable = new MutableLogEvent(); mutable.initFrom(source); assertNull(mutable.getFormat(), "format"); @@ -271,107 +250,4 @@ public void testClear() { assertNotEquals(0, mutable.getThreadPriority(), "tpriority"); } - @Test - public void testJavaIoSerializable() throws Exception { - final MutableLogEvent evt = new MutableLogEvent(); - evt.setContextData(CONTEXT_DATA); - evt.setContextStack(STACK); - evt.setEndOfBatch(true); - evt.setIncludeLocation(true); - evt.setLevel(Level.WARN); - evt.setLoggerFqcn(getClass().getName()); - evt.setLoggerName("loggername"); - evt.setMarker(MarkerManager.getMarker("marked man")); - //evt.setMessage(new ParameterizedMessage("message in a {}", "bottle")); // TODO ParameterizedMessage serialization - evt.setMessage(new SimpleMessage("peace for all")); - evt.setNanoTime(1234); - evt.setThreadId(987); - evt.setThreadName("ito"); - evt.setThreadPriority(9); - evt.setTimeMillis(56789); - - final byte[] binary = serialize(evt); - final Log4jLogEvent evt2 = deserialize(binary); - - assertEquals(evt.getTimeMillis(), evt2.getTimeMillis()); - assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn()); - assertEquals(evt.getLevel(), evt2.getLevel()); - assertEquals(evt.getLoggerName(), evt2.getLoggerName()); - assertEquals(evt.getMarker(), evt2.getMarker()); - assertEquals(evt.getContextData(), evt2.getContextData()); - assertEquals(evt.getContextStack(), evt2.getContextStack()); - assertEquals(evt.getMessage(), evt2.getMessage()); - assertNotNull(evt2.getSource()); - assertEquals(evt.getSource(), evt2.getSource()); - assertEquals(evt.getThreadName(), evt2.getThreadName()); - assertNull(evt2.getThrown()); - assertNull(evt2.getThrownProxy()); - assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch()); - assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation()); - - assertNotEquals(evt.getNanoTime(), evt2.getNanoTime()); // nano time is transient in log4j log event - assertEquals(0, evt2.getNanoTime()); - } - - @Test - public void testJavaIoSerializableWithThrown() throws Exception { - final MutableLogEvent evt = new MutableLogEvent(); - evt.setContextData(CONTEXT_DATA); - evt.setContextStack(STACK); - evt.setEndOfBatch(true); - evt.setIncludeLocation(true); - evt.setLevel(Level.WARN); - evt.setLoggerFqcn(getClass().getName()); - evt.setLoggerName("loggername"); - evt.setMarker(MarkerManager.getMarker("marked man")); - //evt.setMessage(new ParameterizedMessage("message in a {}", "bottle")); // TODO ParameterizedMessage serialization - evt.setMessage(new SimpleMessage("peace for all")); - evt.setNanoTime(1234); - evt.setThreadId(987); - evt.setThreadName("ito"); - evt.setThreadPriority(9); - evt.setThrown(new Exception()); - evt.setTimeMillis(56789); - - final byte[] binary = serialize(evt); - final Log4jLogEvent evt2 = deserialize(binary); - - assertEquals(evt.getTimeMillis(), evt2.getTimeMillis()); - assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn()); - assertEquals(evt.getLevel(), evt2.getLevel()); - assertEquals(evt.getLoggerName(), evt2.getLoggerName()); - assertEquals(evt.getMarker(), evt2.getMarker()); - assertEquals(evt.getContextData(), evt2.getContextData()); - assertEquals(evt.getContextStack(), evt2.getContextStack()); - assertEquals(evt.getMessage(), evt2.getMessage()); - assertNotNull(evt2.getSource()); - assertEquals(evt.getSource(), evt2.getSource()); - assertEquals(evt.getThreadName(), evt2.getThreadName()); - assertNull(evt2.getThrown()); - assertNotNull(evt2.getThrownProxy()); - assertEquals(evt.getThrownProxy(), evt2.getThrownProxy()); - assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch()); - assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation()); - - assertNotEquals(evt.getNanoTime(), evt2.getNanoTime()); // nano time is transient in log4j log event - assertEquals(0, evt2.getNanoTime()); - } - - private byte[] serialize(final MutableLogEvent event) throws IOException { - final ByteArrayOutputStream arr = new ByteArrayOutputStream(); - final ObjectOutputStream out = new ObjectOutputStream(arr); - out.writeObject(event); - return arr.toByteArray(); - } - - @SuppressWarnings("BanSerializableRead") - private Log4jLogEvent deserialize(final byte[] binary) throws IOException, ClassNotFoundException { - final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = useObjectInputStream ? new ObjectInputStream(inArr) : - new FilteredObjectInputStream(inArr); - final Log4jLogEvent result = (Log4jLogEvent) in.readObject(); - return result; - } - - } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromToStringTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromToStringTest.java index 9a9474f5248..bca47b9c4f3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromToStringTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromToStringTest.java @@ -16,16 +16,19 @@ */ package org.apache.logging.log4j.core.impl; +import java.util.List; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; +import org.apache.logging.log4j.spi.LoggingSystemProperties; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import java.util.List; - import static org.junit.Assert.assertEquals; /** @@ -45,6 +48,16 @@ */ public class NestedLoggingFromToStringTest { + @BeforeClass + public static void beforeClass() throws Exception { + System.setProperty(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP, "false"); + } + + @AfterClass + public static void afterClass() throws Exception { + System.clearProperty(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP); + } + @Rule public LoggerContextRule context = new LoggerContextRule("log4j-sync-to-list.xml"); private ListAppender listAppender; @@ -53,7 +66,7 @@ public class NestedLoggingFromToStringTest { @Before public void before() { listAppender = context.getListAppender("List"); - logger = LogManager.getLogger(NestedLoggingFromToStringTest.class); + logger = context.getLogger(NestedLoggingFromToStringTest.class); } static class ParameterizedLoggingThing { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java index 78f071df37a..ee62d4b0eae 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java @@ -23,8 +23,6 @@ import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; -import org.apache.logging.log4j.test.ThreadContextUtilityClass; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.junit.After; @@ -38,7 +36,6 @@ import static java.util.Arrays.asList; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static org.apache.logging.log4j.ThreadContext.getThreadContextMap; -import static org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -78,7 +75,7 @@ private void testContextDataInjector() { (readOnlythreadContextMap == null) ? null : readOnlythreadContextMap.getClass().getName(), is(equalTo(readOnlythreadContextMapClassName))); - ContextDataInjector contextDataInjector = createInjector(); + ContextDataInjector contextDataInjector = ThreadContextDataInjector.create(new DefaultContextDataFactory()); StringMap stringMap = contextDataInjector.injectContextData(null, new SortedArrayStringMap()); assertThat("thread context map", ThreadContext.getContext(), allOf(hasEntry("foo", "bar"), not(hasKey("baz")))); @@ -103,8 +100,7 @@ private void testContextDataInjector() { private void prepareThreadContext(boolean isThreadContextMapInheritable) { System.setProperty(LoggingSystemProperties.THREAD_CONTEXT_MAP_INHERITABLE, Boolean.toString(isThreadContextMapInheritable)); - ((PropertiesUtil) PropertiesUtil.getProperties()).reload(); - ThreadContextUtilityClass.reset(); + ThreadContext.init(); ThreadContext.remove("baz"); ThreadContext.put("foo", "bar"); } @@ -119,12 +115,7 @@ public void testThreadContextImmutability() { public void testInheritableThreadContextImmutability() throws Throwable { prepareThreadContext(true); try { - newSingleThreadExecutor().submit(new Runnable() { - @Override - public void run() { - testContextDataInjector(); - } - }).get(); + newSingleThreadExecutor().submit(this::testContextDataInjector).get(); } catch (ExecutionException ee) { throw ee.getCause(); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java deleted file mode 100644 index e1b3179a1a3..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.pattern.PlainTextRenderer; -import org.apache.logging.log4j.util.Strings; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.spec.IvParameterSpec; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.BindException; -import java.net.InetSocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.security.Permission; -import java.security.SecureRandom; -import java.util.ArrayDeque; -import java.util.Base64; -import java.util.Deque; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * - */ -public class ThrowableProxyTest { - - private static final Base64.Decoder decoder = Base64.getDecoder(); - - public static class AlwaysThrowsError { - static { - if (true) { - throw new Error("I always throw an Error when initialized"); - } - } - } - - static class Fixture { - @JsonProperty - ThrowableProxy proxy = new ThrowableProxy(new IOException("test")); - } - - @SuppressWarnings("BanSerializableRead") - private ThrowableProxy deserialize(final byte[] binary) throws IOException, ClassNotFoundException { - final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new ObjectInputStream(inArr); - return (ThrowableProxy) in.readObject(); - } - - private byte[] serialize(final ThrowableProxy proxy) throws IOException { - final ByteArrayOutputStream arr = new ByteArrayOutputStream(); - final ObjectOutputStream out = new ObjectOutputStream(arr); - out.writeObject(proxy); - return arr.toByteArray(); - } - - private boolean allLinesContain(final String text, final String containedText) { - final String[] lines = text.split("\n"); - for (final String line : lines) { - if (line.isEmpty()) { - continue; - } - if (!line.contains(containedText)) { - return false; - } - } - return true; - } - - private boolean lastLineContains(final String text, final String containedText) { - final String[] lines = text.split("\n"); - final String lastLine = lines[lines.length-1]; - return lastLine.contains(containedText); - } - - private void testIoContainer(final ObjectMapper objectMapper ) throws IOException { - final Fixture expected = new Fixture(); - final String s = objectMapper.writeValueAsString(expected); - final Fixture actual = objectMapper.readValue(s, Fixture.class); - assertEquals(expected.proxy.getName(), actual.proxy.getName()); - assertEquals(expected.proxy.getMessage(), actual.proxy.getMessage()); - assertEquals(expected.proxy.getLocalizedMessage(), actual.proxy.getLocalizedMessage()); - assertEquals(expected.proxy.getCommonElementCount(), actual.proxy.getCommonElementCount()); - assertArrayEquals(expected.proxy.getExtendedStackTrace(), actual.proxy.getExtendedStackTrace()); - assertEquals(expected.proxy, actual.proxy); - } - - /** - * Attempts to instantiate a class that cannot initialize and then logs the stack trace of the Error. The logger - * must not fail when using {@link ThrowableProxy} to inspect the frames of the stack trace. - */ - @Test - public void testLogStackTraceWithClassThatCannotInitialize() { - final Error e = assertThrows(Error.class, AlwaysThrowsError::new); - // Print the stack trace to System.out for informational purposes - // System.err.println("### Here's the stack trace that we'll log with log4j ###"); - // e.printStackTrace(); - // System.err.println("### End stack trace ###"); - - final Logger logger = LogManager.getLogger(getClass()); - - assertDoesNotThrow(() -> { - // This is the critical portion of the test. The log message must be printed without - // throwing a java.lang.Error when introspecting the AlwaysThrowError class in the - // stack trace. - logger.error(e.getMessage(), e); - logger.error(e); - }); - } - - @Test - @DisabledForJreRange(min = JRE.JAVA_18) // custom SecurityManager instances throw UnsupportedOperationException - public void testLogStackTraceWithClassThatWillCauseSecurityException() throws IOException { - final SecurityManager sm = System.getSecurityManager(); - try { - System.setSecurityManager( - new SecurityManager() { - @Override - public void checkPermission(final Permission perm) { - if (perm instanceof RuntimePermission) { - // deny access to the class to trigger the security exception - if ("accessClassInPackage.sun.nio.ch".equals(perm.getName())) { - throw new SecurityException(perm.toString()); - } - } - } - }); - final BindException e = assertThrows(BindException.class, () -> { - ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); - ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); - }); - assertDoesNotThrow(() -> new ThrowableProxy(e)); - } finally { - // restore the security manager - System.setSecurityManager(sm); - } - } - - @Test - @DisabledForJreRange(min = JRE.JAVA_18) // custom SecurityManager instances throw UnsupportedOperationException - public void testLogStackTraceWithClassLoaderThatWithCauseSecurityException() throws Exception { - final SecurityManager sm = System.getSecurityManager(); - try { - System.setSecurityManager( - new SecurityManager() { - @Override - public void checkPermission(final Permission perm) { - if (perm instanceof RuntimePermission) { - // deny access to the classloader to trigger the security exception - if ("getClassLoader".equals(perm.getName())) { - throw new SecurityException(perm.toString()); - } - } - } - }); - final String algorithm = "AES/CBC/PKCS5Padding"; - final Cipher ec = Cipher.getInstance(algorithm); - final byte[] bytes = new byte[16]; // initialization vector - final SecureRandom secureRandom = new SecureRandom(); - secureRandom.nextBytes(bytes); - final KeyGenerator generator = KeyGenerator.getInstance("AES"); - generator.init(128); - final IvParameterSpec algorithmParameterSpec = new IvParameterSpec(bytes); - ec.init(Cipher.ENCRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); - final byte[] raw = new byte[0]; - final byte[] encrypted = ec.doFinal(raw); - final Cipher dc = Cipher.getInstance(algorithm); - dc.init(Cipher.DECRYPT_MODE, generator.generateKey(), algorithmParameterSpec, secureRandom); - final BadPaddingException e = assertThrows(BadPaddingException.class, () -> dc.doFinal(encrypted)); - assertDoesNotThrow(() -> new ThrowableProxy(e)); - } finally { - // restore the existing security manager - System.setSecurityManager(sm); - } - } - - // DO NOT REMOVE THIS COMMENT: - // UNCOMMENT WHEN GENERATING SERIALIZED THROWABLEPROXY FOR #testSerializationWithUnknownThrowable - // public static class DeletedException extends Exception { - // private static final long serialVersionUID = 1L; - // - // public DeletedException(String msg) { - // super(msg); - // } - // }; - - @Test - public void testSerialization() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals(proxy.getName(), proxy2.getName()); - assertEquals(proxy.getMessage(), proxy2.getMessage()); - assertEquals(proxy.getCauseProxy(), proxy2.getCauseProxy()); - assertArrayEquals(proxy.getExtendedStackTrace(), proxy2.getExtendedStackTrace()); - } - - @Test - public void testSerialization_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals(proxy.getExtendedStackTraceAsString(Strings.EMPTY), proxy2.getExtendedStackTraceAsString(Strings.EMPTY)); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth1() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth2() throws Exception { - final Throwable throwable = new RuntimeException( - new IllegalArgumentException("This is a test", new IOException("level 2"))); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - @Test - public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth3() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("level 1", - new IOException("level 2", new IllegalStateException("level 3")))); - testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable); - } - - private void testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(final Throwable throwable) throws Exception { - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final byte[] binary = serialize(proxy); - final ThrowableProxy proxy2 = deserialize(binary); - - assertEquals(proxy.getExtendedStackTraceAsString(Strings.EMPTY), proxy2.getExtendedStackTraceAsString(Strings.EMPTY)); - } - - @Test - public void testSerializationWithUnknownThrowable() throws Exception { - - final String msg = "OMG I've been deleted!"; - - // DO NOT DELETE THIS COMMENT: - // UNCOMMENT TO RE-GENERATE SERIALIZED EVENT WHEN UPDATING THIS TEST. - // final Exception thrown = new DeletedException(msg); - // final ThrowableProxy proxy = new ThrowableProxy(thrown); - // final byte[] binary = serialize(proxy); - // String base64 = DatatypeConverter.printBase64Binary(binary); - // System.out.println("final String base64 = \"" + base64.replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") + "\";"); - - final String base64 = "rO0ABXNyADFvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLlRocm93YWJsZVByb3h52cww1Zp7rPoCAAdJABJjb21tb25FbGVtZW50Q291bnRMAApjYXVzZVByb3h5dAAzTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvVGhyb3dhYmxlUHJveHk7WwASZXh0ZW5kZWRTdGFja1RyYWNldAA/W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7TAAQbG9jYWxpemVkTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAB21lc3NhZ2VxAH4AA0wABG5hbWVxAH4AA1sAEXN1cHByZXNzZWRQcm94aWVzdAA0W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL1Rocm93YWJsZVByb3h5O3hwAAAAAHB1cgA/W0xvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7ys+II6XHz7wCAAB4cAAAABhzcgA8b3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5FeHRlbmRlZFN0YWNrVHJhY2VFbGVtZW504d7Pusa2kAcCAAJMAA5leHRyYUNsYXNzSW5mb3QANkxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkQ2xhc3NJbmZvO0wAEXN0YWNrVHJhY2VFbGVtZW50dAAdTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDt4cHNyADRvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVkQ2xhc3NJbmZvAAAAAAAAAAECAANaAAVleGFjdEwACGxvY2F0aW9ucQB+AANMAAd2ZXJzaW9ucQB+AAN4cAF0AA10ZXN0LWNsYXNzZXMvdAABP3NyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgADTAAIZmlsZU5hbWVxAH4AA0wACm1ldGhvZE5hbWVxAH4AA3hwAAAAaHQANW9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuVGhyb3dhYmxlUHJveHlUZXN0dAAXVGhyb3dhYmxlUHJveHlUZXN0LmphdmF0ACV0ZXN0U2VyaWFsaXphdGlvbldpdGhVbmtub3duVGhyb3dhYmxlc3EAfgAIc3EAfgAMAHEAfgAPdAAIMS43LjBfNTVzcQB+ABD////+dAAkc3VuLnJlZmxlY3QuTmF0aXZlTWV0aG9kQWNjZXNzb3JJbXBscHQAB2ludm9rZTBzcQB+AAhzcQB+AAwAcQB+AA9xAH4AF3NxAH4AEP////9xAH4AGXB0AAZpbnZva2VzcQB+AAhzcQB+AAwAcQB+AA9xAH4AF3NxAH4AEP////90AChzdW4ucmVmbGVjdC5EZWxlZ2F0aW5nTWV0aG9kQWNjZXNzb3JJbXBscHEAfgAec3EAfgAIc3EAfgAMAHEAfgAPcQB+ABdzcQB+ABD/////dAAYamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kcHEAfgAec3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAvdAApb3JnLmp1bml0LnJ1bm5lcnMubW9kZWwuRnJhbWV3b3JrTWV0aG9kJDF0ABRGcmFtZXdvcmtNZXRob2QuamF2YXQAEXJ1blJlZmxlY3RpdmVDYWxsc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAMdAAzb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMubW9kZWwuUmVmbGVjdGl2ZUNhbGxhYmxldAAXUmVmbGVjdGl2ZUNhbGxhYmxlLmphdmF0AANydW5zcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAACx0ACdvcmcuanVuaXQucnVubmVycy5tb2RlbC5GcmFtZXdvcmtNZXRob2RxAH4ALHQAEWludm9rZUV4cGxvc2l2ZWx5c3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAARdAAyb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMuc3RhdGVtZW50cy5JbnZva2VNZXRob2R0ABFJbnZva2VNZXRob2QuamF2YXQACGV2YWx1YXRlc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAEPdAAeb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVydAARUGFyZW50UnVubmVyLmphdmF0AAdydW5MZWFmc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAABGdAAob3JnLmp1bml0LnJ1bm5lcnMuQmxvY2tKVW5pdDRDbGFzc1J1bm5lcnQAG0Jsb2NrSlVuaXQ0Q2xhc3NSdW5uZXIuamF2YXQACHJ1bkNoaWxkc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAAycQB+AE1xAH4ATnEAfgBPc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAADudAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDNxAH4AR3EAfgA0c3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAA/dAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDFxAH4AR3QACHNjaGVkdWxlc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAADscQB+AEZxAH4AR3QAC3J1bkNoaWxkcmVuc3EAfgAIc3EAfgAMAXQADmp1bml0LTQuMTEuamFycQB+AA9zcQB+ABAAAAA1cQB+AEZxAH4AR3QACmFjY2VzcyQwMDBzcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAAOV0ACBvcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXIkMnEAfgBHcQB+AEFzcQB+AAhzcQB+AAwBdAAOanVuaXQtNC4xMS5qYXJxAH4AD3NxAH4AEAAAATVxAH4ARnEAfgBHcQB+ADRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAAAMnQAOm9yZy5lY2xpcHNlLmpkdC5pbnRlcm5hbC5qdW5pdDQucnVubmVyLkpVbml0NFRlc3RSZWZlcmVuY2V0ABhKVW5pdDRUZXN0UmVmZXJlbmNlLmphdmFxAH4ANHNxAH4ACHNxAH4ADAF0AAQuY3AvcQB+AA9zcQB+ABAAAAAmdAAzb3JnLmVjbGlwc2UuamR0LmludGVybmFsLmp1bml0LnJ1bm5lci5UZXN0RXhlY3V0aW9udAASVGVzdEV4ZWN1dGlvbi5qYXZhcQB+ADRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAAB03QANm9yZy5lY2xpcHNlLmpkdC5pbnRlcm5hbC5qdW5pdC5ydW5uZXIuUmVtb3RlVGVzdFJ1bm5lcnQAFVJlbW90ZVRlc3RSdW5uZXIuamF2YXQACHJ1blRlc3Rzc3EAfgAIc3EAfgAMAXQABC5jcC9xAH4AD3NxAH4AEAAAAqtxAH4AgnEAfgCDcQB+AIRzcQB+AAhzcQB+AAwBdAAELmNwL3EAfgAPc3EAfgAQAAABhnEAfgCCcQB+AINxAH4ANHNxAH4ACHNxAH4ADAF0AAQuY3AvcQB+AA9zcQB+ABAAAADFcQB+AIJxAH4Ag3QABG1haW50ABZPTUcgSSd2ZSBiZWVuIGRlbGV0ZWQhcQB+AJJ0AEZvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLlRocm93YWJsZVByb3h5VGVzdCREZWxldGVkRXhjZXB0aW9udXIANFtMb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5UaHJvd2FibGVQcm94eTv67QHghaLrOQIAAHhwAAAAAA=="; - - final byte[] binaryDecoded = decoder.decode(base64); - final ThrowableProxy proxy2 = deserialize(binaryDecoded); - - assertEquals(this.getClass().getName() + "$DeletedException", proxy2.getName()); - assertEquals(msg, proxy2.getMessage()); - } - - @Test - public void testSeparator_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String separator = " | "; - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString(null, - PlainTextRenderer.getInstance(), " | ", Strings.EMPTY); - assertTrue(allLinesContain(extendedStackTraceAsString, separator), extendedStackTraceAsString); - } - - @Test - public void testSuffix_getExtendedStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString(suffix); - assertTrue(lastLineContains(extendedStackTraceAsString, suffix), extendedStackTraceAsString); - } - - @Test - public void testSuffix_getExtendedStackTraceAsStringWithCausedThrowable() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getExtendedStackTraceAsStringWithSuppressedThrowable() throws Exception { - final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); - final Throwable throwable = new RuntimeException(cause); - throwable.addSuppressed(new IOException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getExtendedStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsString() throws Exception { - final Throwable throwable = new IllegalArgumentException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsStringWithCausedThrowable() throws Exception { - final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testSuffix_getCauseStackTraceAsStringWithSuppressedThrowable() throws Exception { - final IllegalArgumentException cause = new IllegalArgumentException("This is a test"); - final Throwable throwable = new RuntimeException(cause); - throwable.addSuppressed(new IOException("This is a test")); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - - final String suffix = "some suffix"; - assertTrue(allLinesContain(proxy.getCauseStackTraceAsString(suffix), suffix)); - } - - @Test - public void testStack() { - final Map map = new HashMap<>(); - final Deque> stack = new ArrayDeque<>(); - final Throwable throwable = new IllegalStateException("This is a test"); - final ThrowableProxy proxy = new ThrowableProxy(throwable); - final ExtendedStackTraceElement[] callerPackageData = ThrowableProxyHelper.toExtendedStackTrace(proxy, stack, map, null, - throwable.getStackTrace()); - assertNotNull(callerPackageData, "No package data returned"); - } - - /** - * Asserts that LOG4J2-834 is solved by constructing a ThrowableProxy over a RuntimeException object thrown at a - * unloaded known class (already compiled and available as a test resource: - * org.apache.logging.log4j.core.impl.ForceNoDefClassFoundError.class). - */ - @SuppressWarnings("BanSerializableRead") - @Test - public void testStackWithUnloadableClass() throws Exception { - final Deque> stack = new ArrayDeque<>(); - final Map map = new HashMap<>(); - - final String runtimeExceptionThrownAtUnloadableClass_base64 = "rO0ABXNyABpqYXZhLmxhbmcuUnVudGltZUV4Y2VwdGlvbp5fBkcKNIPlAgAAeHIAE2phdmEubGFuZy5FeGNlcHRpb27Q/R8+GjscxAIAAHhyABNqYXZhLmxhbmcuVGhyb3dhYmxl1cY1Jzl3uMsDAANMAAVjYXVzZXQAFUxqYXZhL2xhbmcvVGhyb3dhYmxlO0wADWRldGFpbE1lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApzdGFja1RyYWNldAAeW0xqYXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7eHBxAH4ABnB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnQ7AkYqPDz9IjkCAAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50YQnFmiY23YUCAARJAApsaW5lTnVtYmVyTAAOZGVjbGFyaW5nQ2xhc3NxAH4ABEwACGZpbGVOYW1lcQB+AARMAAptZXRob2ROYW1lcQB+AAR4cAAAAAZ0ADxvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkZvcmNlTm9EZWZDbGFzc0ZvdW5kRXJyb3J0AB5Gb3JjZU5vRGVmQ2xhc3NGb3VuZEVycm9yLmphdmF0AARtYWlueA=="; - final byte[] binaryDecoded = decoder.decode(runtimeExceptionThrownAtUnloadableClass_base64); - final ByteArrayInputStream inArr = new ByteArrayInputStream(binaryDecoded); - final ObjectInputStream in = new ObjectInputStream(inArr); - final Throwable throwable = (Throwable) in.readObject(); - final ThrowableProxy subject = new ThrowableProxy(throwable); - - ThrowableProxyHelper.toExtendedStackTrace(subject, stack, map, null, throwable.getStackTrace()); - } - - /** - * Tests LOG4J2-934. - */ - @Test - public void testCircularSuppressedExceptions() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(); - e2.addSuppressed(e1); - e1.addSuppressed(e2); - LogManager.getLogger().error("Error", e1); - } - - @Test - public void testSuppressedExceptions() { - final Exception e = new Exception("Root exception"); - e.addSuppressed(new IOException("Suppressed #1")); - e.addSuppressed(new IOException("Suppressed #2")); - LogManager.getLogger().error("Error", e); - final ThrowableProxy proxy = new ThrowableProxy(e); - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - } - - @Test - public void testCauseSuppressedExceptions() { - final Exception cause = new Exception("Nested exception"); - cause.addSuppressed(new IOException("Suppressed #1")); - cause.addSuppressed(new IOException("Suppressed #2")); - LogManager.getLogger().error("Error", new Exception(cause)); - final ThrowableProxy proxy = new ThrowableProxy(new Exception("Root exception", cause)); - final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString("same suffix"); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1")); - } - - /** - * Tests LOG4J2-934. - */ - @Test - public void testCircularSuppressedNestedException() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(e1); - e2.addSuppressed(e1); - e1.addSuppressed(e2); - LogManager.getLogger().error("Error", e1); - } - - /** - * . - */ - @Test - public void testCircularCauseExceptions() { - final Exception e1 = new Exception(); - final Exception e2 = new Exception(e1); - e1.initCause(e2); - LogManager.getLogger().error("Error", e1); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java index 65855348f3d..fba968e47ba 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java @@ -1,4 +1,4 @@ -package org.apache.logging.log4j.core.layout;/* +/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -14,6 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ +package org.apache.logging.log4j.core.layout; import java.nio.charset.Charset; @@ -34,10 +35,6 @@ public ConcreteStringLayout() { super(Charset.defaultCharset()); } - public static StringBuilder getStringBuilder() { - return AbstractStringLayout.getStringBuilder(); - } - @Override public String toSerializable(final LogEvent event) { return null; @@ -46,7 +43,8 @@ public String toSerializable(final LogEvent event) { @Test public void testGetStringBuilderCapacityRestrictedToMax() throws Exception { - final StringBuilder sb = ConcreteStringLayout.getStringBuilder(); + final ConcreteStringLayout layout = new ConcreteStringLayout(); + final StringBuilder sb = layout.getStringBuilder(); final int initialCapacity = sb.capacity(); assertEquals(ConcreteStringLayout.DEFAULT_STRING_BUILDER_SIZE, sb.capacity(), "initial capacity"); @@ -56,7 +54,7 @@ public void testGetStringBuilderCapacityRestrictedToMax() throws Exception { assertEquals(initialCapacity, sb.capacity(), "capacity not grown"); assertEquals(SMALL, sb.length(), "length=msg length"); - final StringBuilder sb2 = ConcreteStringLayout.getStringBuilder(); + final StringBuilder sb2 = layout.getStringBuilder(); assertEquals(sb2.capacity(), initialCapacity, "capacity unchanged"); assertEquals(0, sb2.length(), "empty, ready for use"); @@ -71,7 +69,7 @@ public void testGetStringBuilderCapacityRestrictedToMax() throws Exception { assertEquals(0, sb2.length(), "empty, cleared"); assertTrue(sb2.capacity() >= ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, "capacity remains very large"); - final StringBuilder sb3 = ConcreteStringLayout.getStringBuilder(); + final StringBuilder sb3 = layout.getStringBuilder(); assertEquals(ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, sb3.capacity(), "capacity, trimmed to MAX_STRING_BUILDER_SIZE"); assertEquals(0, sb3.length(), "empty, ready for use"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java index 0a45fca98b1..b2e23358c50 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java @@ -29,7 +29,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.*; +import org.apache.logging.log4j.core.AbstractLogEvent; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.test.BasicConfigurationFactory; import org.apache.logging.log4j.core.test.appender.ListAppender; @@ -50,7 +54,6 @@ @UsingAnyThreadContext public class HtmlLayoutTest { private static class MyLogEvent extends AbstractLogEvent { - private static final long serialVersionUID = 0; @Override public Instant getInstant() { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Log4j2_2195_Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Log4j2_2195_Test.java index 42c3b97e836..93d5ea81366 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Log4j2_2195_Test.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Log4j2_2195_Test.java @@ -14,18 +14,16 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.layout; -import java.io.Serializable; import java.util.List; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer; +import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.test.junit.Named; -import org.apache.logging.log4j.core.test.appender.ListAppender; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -46,7 +44,7 @@ public void test(final LoggerContext context, @Named("ListAppender") final ListA assertFalse(logEvent.contains("org.junit"), "\"org.junit\" should not be here"); assertFalse(logEvent.contains("org.eclipse"), "\"org.eclipse\" should not be here"); // - Layout layout = listAppender.getLayout(); + Layout layout = listAppender.getLayout(); PatternLayout pLayout = (PatternLayout) layout; assertNotNull(pLayout); Serializer eventSerializer = pLayout.getEventSerializer(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java index 3cc58cc5ced..68d3d831e90 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java @@ -28,7 +28,6 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.lookup.MainMapLookup; import org.apache.logging.log4j.core.test.BasicConfigurationFactory; import org.apache.logging.log4j.message.SimpleMessage; @@ -101,22 +100,22 @@ private void assertEncode(final String expectedStr, final PatternLayout layout, public void testEqualsEmptyMarker() throws Exception { // replace "[]" with the empty string final PatternLayout layout = PatternLayout.newBuilder().setPattern("[%logger]%equals{[%marker]}{[]}{} %msg") - .setConfiguration(ctx.getConfiguration()).build(); + .setConfiguration(ctx.getConfiguration()).get(); // Not empty marker - final LogEvent event1 = Log4jLogEvent.newBuilder() // + final LogEvent event1 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // .setMarker(MarkerManager.getMarker("TestMarker")) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")).get(); assertToByteArray("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker] Hello, world!", layout, event1); assertEncode("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker] Hello, world!", layout, event1); // empty marker - final LogEvent event2 = Log4jLogEvent.newBuilder() // + final LogEvent event2 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")).get(); assertToByteArray("[org.apache.logging.log4j.core.layout.PatternLayoutTest] Hello, world!", layout, event2); assertEncode("[org.apache.logging.log4j.core.layout.PatternLayoutTest] Hello, world!", layout, event2); } @@ -188,10 +187,10 @@ private void testMdcPattern(final String patternStr, final String expectedStr, f ThreadContext.put("key1", "value1"); ThreadContext.put("key2", "value2"); } - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello")).build(); + .setMessage(new SimpleMessage("Hello")).get(); assertToByteArray(expectedStr, layout, event); assertEncode(expectedStr, layout, event); } @@ -241,19 +240,21 @@ public void testPatternSelector() throws Exception { // @formatter:on final PatternLayout layout = PatternLayout.newBuilder().setPatternSelector(selector) .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // + final LogEvent event1 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternLayoutTest$FauxLogger") .setMarker(MarkerManager.getMarker("FLOW")) .setLevel(Level.TRACE) // - .setIncludeLocation(true) - .setMessage(new SimpleMessage("entry")).build(); + .includeLocation(true) + .setMessage(new SimpleMessage("entry")) + .get(); final String result1 = new FauxLogger().formatEvent(event1, layout); final String expectPattern1 = String.format(".*====== PatternLayoutTest.testPatternSelector:\\d+ entry ======%n"); assertTrue(result1.matches(expectPattern1), "Unexpected result: " + result1); - final LogEvent event2 = Log4jLogEvent.newBuilder() // + final LogEvent event2 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result2 = new String(layout.toByteArray(event2)); final String expectSuffix2 = String.format("Hello, world 1!%n"); assertTrue(result2.endsWith(expectSuffix2), "Unexpected result: " + result2); @@ -263,10 +264,12 @@ public void testPatternSelector() throws Exception { public void testRegex() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern(regexPattern) .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertToByteArray("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", layout, event); assertEncode("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", layout, event); } @@ -277,21 +280,24 @@ public void testRegexEmptyMarker() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("[%logger]%replace{[%marker]}{\\[\\]}{} %msg") .setConfiguration(ctx.getConfiguration()).build(); // Not empty marker - final LogEvent event1 = Log4jLogEvent.newBuilder() // + final LogEvent event1 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // .setMarker(MarkerManager.getMarker("TestMarker")) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertToByteArray("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker] Hello, world!", layout, event1); assertEncode("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker] Hello, world!", layout, event1); // empty marker - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event2 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertToByteArray("[org.apache.logging.log4j.core.layout.PatternLayoutTest] Hello, world!", layout, event2); assertEncode("[org.apache.logging.log4j.core.layout.PatternLayoutTest] Hello, world!", layout, event2); } @@ -302,18 +308,22 @@ public void testEqualsMarkerWithMessageSubstitution() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("[%logger]%equals{[%marker]}{[]}{[%msg]}") .setConfiguration(ctx.getConfiguration()).build(); // Not empty marker - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event1 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // .setMarker(MarkerManager.getMarker("TestMarker")) - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final byte[] result1 = layout.toByteArray(event1); assertEquals("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker]", new String(result1)); // empty marker - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event2 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final byte[] result2 = layout.toByteArray(event2); assertEquals("[org.apache.logging.log4j.core.layout.PatternLayoutTest][Hello, world!]", new String(result2)); } @@ -322,10 +332,12 @@ public void testEqualsMarkerWithMessageSubstitution() throws Exception { public void testSpecialChars() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("\\\\%level\\t%msg\\n\\t%logger\\r\\n\\f") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); assertToByteArray("\\INFO\tHello, world!\n" + "\torg.apache.logging.log4j.core.layout.PatternLayoutTest\r\n" + "\f", layout, event); @@ -338,17 +350,21 @@ public void testSpecialChars() throws Exception { public void testUnixTime() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%d{UNIX} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event1 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final byte[] result1 = layout.toByteArray(event1); assertEquals(event1.getTimeMillis() / 1000 + " Hello, world 1!", new String(result1)); // System.out.println("event1=" + event1.getTimeMillis() / 1000); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event2 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); + .setMessage(new SimpleMessage("Hello, world 2!")) + .get(); final byte[] result2 = layout.toByteArray(event2); assertEquals(event2.getTimeMillis() / 1000 + " Hello, world 2!", new String(result2)); // System.out.println("event2=" + event2.getTimeMillis() / 1000); @@ -358,17 +374,17 @@ public void testUnixTime() throws Exception { private void testUnixTime(final String pattern) throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern(pattern + " %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // + final LogEvent event1 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")).get(); final byte[] result1 = layout.toByteArray(event1); assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); // System.out.println("event1=" + event1.getMillis()); - final LogEvent event2 = Log4jLogEvent.newBuilder() // + final LogEvent event2 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); + .setMessage(new SimpleMessage("Hello, world 2!")).get(); final byte[] result2 = layout.toByteArray(event2); assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); // System.out.println("event2=" + event2.getMillis()); @@ -378,17 +394,17 @@ private void testUnixTime(final String pattern) throws Exception { public void testUnixTimeMillis() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%d{UNIX_MILLIS} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // + final LogEvent event1 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")).get(); final byte[] result1 = layout.toByteArray(event1); assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); // System.out.println("event1=" + event1.getTimeMillis()); - final LogEvent event2 = Log4jLogEvent.newBuilder() // + final LogEvent event2 = LogEvent.builder() // .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); + .setMessage(new SimpleMessage("Hello, world 2!")).get(); final byte[] result2 = layout.toByteArray(event2); assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); // System.out.println("event2=" + event2.getTimeMillis()); @@ -413,20 +429,20 @@ public void testLoggerNameTruncationByRetainingPartsFromEnd() throws Exception { { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{1} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")).get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1)); } { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{2} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")).get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(0, this.getClass().getName().lastIndexOf(".")); name = name.substring(0, name.lastIndexOf(".")); @@ -435,10 +451,10 @@ public void testLoggerNameTruncationByRetainingPartsFromEnd() throws Exception { { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{20} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")).get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1)); } @@ -449,24 +465,24 @@ public void testCallersFqcnTruncationByRetainingPartsFromEnd() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{1} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1)); } { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{2} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(0, this.getClass().getName().lastIndexOf(".")); name = name.substring(0, name.lastIndexOf(".")); @@ -475,24 +491,24 @@ public void testCallersFqcnTruncationByRetainingPartsFromEnd() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{20} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1)); } { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%class{1} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1)); } @@ -503,10 +519,12 @@ public void testLoggerNameTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{-1} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") + final LogEvent event1 = LogEvent.builder() + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result1 = layout.toSerializable(event1); final String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); assertEquals(name + " Hello, world 1!", new String(result1)); @@ -514,10 +532,12 @@ public void testLoggerNameTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{-3} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") + final LogEvent event1 = LogEvent.builder() + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); name = name.substring(name.indexOf(".") + 1); @@ -527,10 +547,12 @@ public void testLoggerNameTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%logger{-3} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") + final LogEvent event1 = LogEvent.builder() + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); name = name.substring(name.indexOf(".") + 1); @@ -540,10 +562,12 @@ public void testLoggerNameTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%c{-20} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") + final LogEvent event1 = LogEvent.builder() + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1)); } @@ -555,12 +579,12 @@ public void testCallersFqcnTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{-1} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); final String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); assertEquals(name + " Hello, world 1!", new String(result1)); @@ -568,12 +592,13 @@ public void testCallersFqcnTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{-3} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") + final LogEvent event1 = LogEvent.builder() + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); name = name.substring(name.indexOf(".") + 1); @@ -583,12 +608,12 @@ public void testCallersFqcnTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%class{-3} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1); name = name.substring(name.indexOf(".") + 1); @@ -598,12 +623,12 @@ public void testCallersFqcnTruncationByDroppingPartsFromFront() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().setPattern("%C{-20} %m") .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() + final LogEvent event1 = LogEvent.builder() .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, world 1!")) .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546)) - .build(); + .get(); final String result1 = layout.toSerializable(event1); assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1)); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java index eb5b3b5400d..dac59ea1c0e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java @@ -21,11 +21,10 @@ import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; public class PatternSelectorTest { @@ -52,19 +51,23 @@ public void testMarkerPatternSelector() throws Exception { // @formatter:on final PatternLayout layout = PatternLayout.newBuilder().setPatternSelector(selector) .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger") + final LogEvent event1 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger") .setMarker(MarkerManager.getMarker("FLOW")) .setLevel(Level.TRACE) // - .setIncludeLocation(true) - .setMessage(new SimpleMessage("entry")).build(); + .includeLocation(true) + .setMessage(new SimpleMessage("entry")) + .get(); final String result1 = new FauxLogger().formatEvent(event1, layout); final String expectSuffix1 = String.format("====== PatternSelectorTest.testMarkerPatternSelector:61 entry ======%n"); assertTrue(result1.endsWith(expectSuffix1), "Unexpected result: " + result1); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event2 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result2 = new String(layout.toByteArray(event2)); final String expectSuffix2 = String.format("Hello, world 1!%n"); assertTrue(result2.endsWith(expectSuffix2), "Unexpected result: " + result2); @@ -77,18 +80,22 @@ public void testLevelPatternSelector() throws Exception { final PatternSelector selector = LevelPatternSelector.createSelector(patterns, "%d %-5p [%t]: %m%n", true, true, ctx.getConfiguration()); final PatternLayout layout = PatternLayout.newBuilder().setPatternSelector(selector) .setConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger") + final LogEvent event1 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger") .setLevel(Level.TRACE) // - .setIncludeLocation(true) - .setMessage(new SimpleMessage("entry")).build(); + .includeLocation(true) + .setMessage(new SimpleMessage("entry")) + .get(); final String result1 = new FauxLogger().formatEvent(event1, layout); final String expectSuffix1 = String.format("====== PatternSelectorTest.testLevelPatternSelector:85 entry ======%n"); assertTrue(result1.endsWith(expectSuffix1), "Unexpected result: " + result1); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + final LogEvent event2 = LogEvent.builder() // + .setLoggerName(this.getClass().getName()) + .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); + .setMessage(new SimpleMessage("Hello, world 1!")) + .get(); final String result2 = new String(layout.toByteArray(event2)); final String expectSuffix2 = String.format("Hello, world 1!%n"); assertTrue(result2.endsWith(expectSuffix2), "Unexpected result: " + result2); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/ContextMapLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/ContextMapLookupTest.java index 57421a35286..59d15c845e3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/ContextMapLookupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/ContextMapLookupTest.java @@ -21,6 +21,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; @@ -59,7 +60,7 @@ public void evaluate() throws Throwable { @Test public void testLookup() { ThreadContext.put(TESTKEY, TESTVAL); - final StrLookup lookup = new ContextMapLookup(); + final StrLookup lookup = new ContextMapLookup(() -> context.getLoggerContext().getInstance(ContextDataInjector.class)); String value = lookup.lookup(TESTKEY); assertEquals(TESTVAL, value); value = lookup.lookup("BadKey"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/EventLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/EventLookupTest.java index 25006d2a207..e1447062616 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/EventLookupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/EventLookupTest.java @@ -20,11 +20,10 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests {@link MarkerLookup}. @@ -40,12 +39,13 @@ public class EventLookupTest { @Test public void testLookupEventMarker() { final Marker marker = MarkerManager.getMarker(markerName); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setMarker(marker) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final String value = strLookup.lookup(event, "Marker"); assertEquals(markerName, value); } @@ -53,11 +53,12 @@ public void testLookupEventMarker() { @Test public void testLookupEventMessage() { String msg = "Hello, world!"; - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage(msg)).build(); + .setMessage(new SimpleMessage(msg)) + .get(); final String value = strLookup.lookup(event, "Message"); assertEquals(msg, value); } @@ -65,11 +66,12 @@ public void testLookupEventMessage() { @Test public void testLookupEventLevel() { String msg = "Hello, world!"; - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage(msg)).build(); + .setMessage(new SimpleMessage(msg)) + .get(); final String value = strLookup.lookup(event, "Level"); assertEquals(Level.INFO.toString(), value); } @@ -78,12 +80,13 @@ public void testLookupEventLevel() { public void testLookupEventTimestamp() { String msg = "Hello, world!"; long now = System.currentTimeMillis(); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setTimeMillis(now) .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage(msg)).build(); + .setMessage(new SimpleMessage(msg)) + .get(); final String value = strLookup.lookup(event, "Timestamp"); assertEquals(Long.toString(now), value); } @@ -91,11 +94,12 @@ public void testLookupEventTimestamp() { @Test public void testLookupEventLogger() { String msg = "Hello, world!"; - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage(msg)).build(); + .setMessage(new SimpleMessage(msg)) + .get(); final String value = strLookup.lookup(event, "Logger"); assertEquals(this.getClass().getName(), value); } @@ -103,12 +107,13 @@ public void testLookupEventLogger() { @Test public void testLookupEventThreadName() { String msg = "Hello, world!"; - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setThreadName("Main") .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage(msg)).build(); + .setMessage(new SimpleMessage(msg)) + .get(); final String value = strLookup.lookup(event, "ThreadName"); assertEquals("Main", value); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java index 10002f73720..73cc995ae4f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java @@ -26,17 +26,13 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.StringMapMessage; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertSame; -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.*; /** * @@ -128,12 +124,12 @@ public void testInterpolatorMapMessageWithNoPrefix() { Interpolator interpolator = new Interpolator(configProperties); final HashMap map = new HashMap<>(); map.put("key", "mapMessage"); - LogEvent event = Log4jLogEvent.newBuilder() + LogEvent event = LogEvent.builder() .setLoggerName(getClass().getName()) .setLoggerFqcn(Logger.class.getName()) .setLevel(Level.INFO) .setMessage(new StringMapMessage(map)) - .build(); + .get(); assertEquals("configProperties", interpolator.lookup(event, "key")); } @@ -142,12 +138,12 @@ public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() { Interpolator interpolator = new Interpolator(Collections.emptyMap()); final HashMap map = new HashMap<>(); map.put("key", "mapMessage"); - LogEvent event = Log4jLogEvent.newBuilder() + LogEvent event = LogEvent.builder() .setLoggerName(getClass().getName()) .setLoggerFqcn(Logger.class.getName()) .setLevel(Level.INFO) .setMessage(new StringMapMessage(map)) - .build(); + .get(); assertNull( interpolator.lookup(event, "key"), "Values without a map prefix should not match MapMessages"); @@ -160,12 +156,12 @@ public void testInterpolatorMapMessageWithMapPrefix() { Interpolator interpolator = new Interpolator(configProperties); final HashMap map = new HashMap<>(); map.put("key", "mapMessage"); - LogEvent event = Log4jLogEvent.newBuilder() + LogEvent event = LogEvent.builder() .setLoggerName(getClass().getName()) .setLoggerFqcn(Logger.class.getName()) .setLevel(Level.INFO) .setMessage(new StringMapMessage(map)) - .build(); + .get(); assertEquals("mapMessage", interpolator.lookup(event, "map:key")); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MapLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MapLookupTest.java index 426c717f318..f21ac707be9 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MapLookupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MapLookupTest.java @@ -19,12 +19,12 @@ import java.util.HashMap; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * Tests {@link MapLookup}. @@ -73,7 +73,7 @@ public void testEventStringMapMessage() { final HashMap eventMap = new HashMap<>(); eventMap.put("A1", "B1"); final StringMapMessage message = new StringMapMessage(eventMap); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setMessage(message) .build(); final MapLookup lookup = new MapLookup(map); @@ -88,7 +88,7 @@ public void testEventMapMessage() { final HashMap eventMap = new HashMap<>(); eventMap.put("A1", 11); final MapMessage message = new MapMessage<>(eventMap); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setMessage(message) .build(); final MapLookup lookup = new MapLookup(map); @@ -104,7 +104,7 @@ public void testLookupMapMessageIsCheckedBeforeDefaultMap() { final HashMap eventMap = new HashMap<>(); eventMap.put("A", "AEvent"); final MapMessage message = new MapMessage<>(eventMap); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setMessage(message) .build(); final MapLookup lookup = new MapLookup(map); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupTest.java index f55121e28d0..c06427ccf8e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupTest.java @@ -20,11 +20,11 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * Tests {@link MarkerLookup}. @@ -40,23 +40,25 @@ public class MarkerLookupTest { @Test public void testLookupEventExistant() { final Marker marker = MarkerManager.getMarker(markerName); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setMarker(marker) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final String value = strLookup.lookup(event, marker.getName()); assertEquals(markerName, value); } @Test public void testLookupEventNonExistant() { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final String value = strLookup.lookup(event, ABSENT_MARKER_NAME); assertNull(value); } @@ -64,12 +66,13 @@ public void testLookupEventNonExistant() { @Test public void testLookupEventNonExistantKey() { final Marker marker = MarkerManager.getMarker(markerName); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(this.getClass().getName()) // .setMarker(marker) // .setLoggerFqcn("org.apache.logging.log4j.core.Logger") // .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); + .setMessage(new SimpleMessage("Hello, world!")) + .get(); final String value = strLookup.lookup(event, ABSENT_MARKER_NAME); assertEquals(markerName, value); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java index 976bbb32a74..8cd1cfea755 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java @@ -21,9 +21,12 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.test.junit.StatusLoggerLevel; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,11 +48,20 @@ public static void after() { System.clearProperty(TESTKEY); } + private InterpolatorFactory interpolatorFactory; + + @BeforeEach + void setUp() { + final Injector injector = DI.createInjector(); + injector.init(); + interpolatorFactory = injector.getInstance(InterpolatorFactory.class); + } + @Test public void testLookup() { final Map map = new HashMap<>(); map.put(TESTKEY, TESTVAL); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); ThreadContext.put(TESTKEY, TESTVAL); String value = subst.replace("${TestKey}-${ctx:TestKey}-${sys:TestKey}"); @@ -164,7 +176,7 @@ public void testValueEscapeDelimiter() { public void testDefault() { final Map map = new HashMap<>(); map.put(TESTKEY, TESTVAL); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); ThreadContext.put(TESTKEY, TESTVAL); //String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); @@ -176,7 +188,7 @@ public void testDefault() { public void testDefaultReferencesLookupValue() { final Map map = new HashMap<>(); map.put(TESTKEY, "${java:version}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); @@ -185,7 +197,7 @@ public void testDefaultReferencesLookupValue() { @Test public void testInfiniteSubstitutionOnString() { - final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(new HashMap<>())); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; @@ -194,7 +206,7 @@ public void testInfiniteSubstitutionOnString() { @Test public void testInfiniteSubstitutionOnStringBuilder() { - final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(new HashMap<>())); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; @@ -206,7 +218,7 @@ public void testRecursiveSubstitution() { final Map map = new HashMap<>(); map.put("first", "${ctx:first}"); map.put("second", "secondValue"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); assertEquals("${ctx:first} and secondValue", subst.replace("${ctx:first} and ${ctx:second}")); @@ -216,7 +228,7 @@ public void testRecursiveSubstitution() { public void testRecursiveWithDefault() { final Map map = new HashMap<>(); map.put("first", "${ctx:first:-default}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); assertEquals("default", subst.replace("${ctx:first}")); @@ -226,7 +238,7 @@ public void testRecursiveWithDefault() { public void testRecursiveWithRecursiveDefault() { final Map map = new HashMap<>(); map.put("first", "${ctx:first:-${ctx:first}}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); assertEquals("${ctx:first}", subst.replace("${ctx:first}")); @@ -236,7 +248,7 @@ public void testRecursiveWithRecursiveDefault() { public void testNestedSelfReferenceWithRecursiveEvaluation() { final Map map = new HashMap<>(); map.put("first", "${${ctx:first}}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); assertEquals("${${ctx:first}}", subst.replace("${ctx:first}")); @@ -246,7 +258,7 @@ public void testNestedSelfReferenceWithRecursiveEvaluation() { public void testRandomWithRecursiveDefault() { final Map map = new HashMap<>(); map.put("first", "${env:RANDOM:-${ctx:first}}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(true); assertEquals("${ctx:first}", subst.replace("${ctx:first}")); @@ -257,7 +269,7 @@ public void testNoRecursiveEvaluationWithDefault() { final Map map = new HashMap<>(); map.put("first", "${java:version}"); map.put("second", "${java:runtime}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("${java:version}", subst.replace("${ctx:first:-${ctx:second}}")); @@ -267,7 +279,7 @@ public void testNoRecursiveEvaluationWithDefault() { public void testNoRecursiveEvaluationWithDepthOne() { final Map map = new HashMap<>(); map.put("first", "${java:version}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("${java:version}", subst.replace("${ctx:first}")); @@ -277,7 +289,7 @@ public void testNoRecursiveEvaluationWithDepthOne() { public void testLookupsNestedWithoutRecursiveEvaluation() { final Map map = new HashMap<>(); map.put("first", "${java:version}"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("${java:version}", subst.replace("${${lower:C}t${lower:X}:first}")); @@ -308,7 +320,7 @@ public String lookup(LogEvent event, String key) { public void testTopLevelLookupsWithoutRecursiveEvaluation() { final Map map = new HashMap<>(); map.put("key", "VaLuE"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("value", subst.replace("${lower:${ctx:key}}")); @@ -318,7 +330,7 @@ public void testTopLevelLookupsWithoutRecursiveEvaluation() { public void testTopLevelLookupsWithoutRecursiveEvaluation_doubleLower() { final Map map = new HashMap<>(); map.put("key", "VaLuE"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("value", subst.replace("${lower:${lower:${ctx:key}}}")); @@ -328,7 +340,7 @@ public void testTopLevelLookupsWithoutRecursiveEvaluation_doubleLower() { public void testTopLevelLookupsWithoutRecursiveEvaluationAndDefaultValueLookup() { final Map map = new HashMap<>(); map.put("key2", "TWO"); - final StrLookup lookup = new Interpolator(new MapLookup(map)); + final StrLookup lookup = interpolatorFactory.newInterpolator(new MapLookup(map)); final StrSubstitutor subst = new StrSubstitutor(lookup); subst.setRecursiveEvaluationAllowed(false); assertEquals("two", subst.replace("${lower:${ctx:key1:-${ctx:key2}}}")); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StructuredDataLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StructuredDataLookupTest.java index 737ff418e79..75027f1a539 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StructuredDataLookupTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StructuredDataLookupTest.java @@ -18,12 +18,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.StructuredDataMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class StructuredDataLookupTest { @@ -33,7 +33,7 @@ public class StructuredDataLookupTest { @Test public void testLookup() { final Message msg = new StructuredDataMessage("Test", "This is a test", "Audit"); - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(msg).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.DEBUG).setMessage(msg).get(); final StrLookup lookup = new StructuredDataLookup(); String value = lookup.lookup(event, TESTKEY); assertEquals(TESTVAL, value); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java index e84e156bf09..bd5840ade89 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java @@ -16,18 +16,6 @@ */ package org.apache.logging.log4j.core.net; -import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; -import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; -import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; -import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED; -import static javax.servlet.http.HttpServletResponse.SC_OK; -import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -39,14 +27,17 @@ import java.nio.file.Files; import java.util.Base64; import java.util.Enumeration; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.ConfigurationResolver; import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -55,10 +46,15 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.SetSystemProperty; import com.sun.management.UnixOperatingSystemMXBean; +import static javax.servlet.http.HttpServletResponse.*; +import static org.junit.jupiter.api.Assertions.*; + /** * Tests the UrlConnectionFactory */ @@ -70,7 +66,6 @@ public class UrlConnectionFactoryTest { private static Server server; private static final Base64.Decoder decoder = Base64.getDecoder(); private static int port; - private static final int BUF_SIZE = 1024; @BeforeAll public static void startServer() throws Exception { @@ -97,24 +92,33 @@ public static void stopServer() throws Exception { server.stop(); } + private UrlConnectionFactory urlConnectionFactory; + private ConfigurationResolver configurationResolver; + + @BeforeEach + void setUp() { + final Injector injector = DI.createInjector(); + injector.init(); + urlConnectionFactory = injector.getInstance(UrlConnectionFactory.class); + configurationResolver = injector.getInstance(ConfigurationResolver.class); + } + @Test - public void testBadCrdentials() throws Exception { - System.setProperty("log4j2.Configuration.username", "foo"); - System.setProperty("log4j2.Configuration.password", "bar"); - System.setProperty("log4j2.Configuration.allowedProtocols", "http"); + @SetSystemProperty(key = Log4jProperties.TRANSPORT_SECURITY_BASIC_USERNAME, value = "foo") + @SetSystemProperty(key = Log4jProperties.TRANSPORT_SECURITY_BASIC_PASSWORD, value = "bar") + @SetSystemProperty(key = Log4jProperties.CONFIG_ALLOWED_PROTOCOLS, value = "http") + public void testBadCredentials() throws Exception { final URI uri = new URI("http://localhost:" + port + "/log4j2-config.xml"); - final ConfigurationSource source = ConfigurationSource.fromUri(uri); - assertNull(source, "A ConfigurationSource should not have been returned"); + assertTrue(configurationResolver.tryResolve(uri).isEmpty(), "A ConfigurationSource should not have been returned"); } @Test + @SetSystemProperty(key = Log4jProperties.TRANSPORT_SECURITY_BASIC_USERNAME, value = "testuser") + @SetSystemProperty(key = Log4jProperties.TRANSPORT_SECURITY_BASIC_PASSWORD, value = "password") + @SetSystemProperty(key = Log4jProperties.CONFIG_ALLOWED_PROTOCOLS, value = "http") public void withAuthentication() throws Exception { - System.setProperty("log4j2.Configuration.username", "testuser"); - System.setProperty("log4j2.Configuration.password", "password"); - System.setProperty("log4j2.Configuration.allowedProtocols", "http"); final URI uri = new URI("http://localhost:" + port + "/log4j2-config.xml"); - final ConfigurationSource source = ConfigurationSource.fromUri(uri); - assertNotNull(source, "No ConfigurationSource returned"); + final ConfigurationSource source = configurationResolver.tryResolve(uri).orElseThrow(); InputStream is = source.getInputStream(); assertNotNull(is, "No data returned"); is.close(); @@ -130,8 +134,7 @@ public void withAuthentication() throws Exception { } private int verifyNotModified(final URI uri, final long lastModifiedMillis) throws Exception { - final HttpURLConnection urlConnection = UrlConnectionFactory.createConnection(uri.toURL(), - lastModifiedMillis, null, null); + final HttpURLConnection urlConnection = urlConnectionFactory.openConnection(uri.toURL(), lastModifiedMillis); urlConnection.connect(); try { @@ -146,15 +149,15 @@ private int verifyNotModified(final URI uri, final long lastModifiedMillis) thro public void testNoJarFileLeak() throws Exception { final URL url = new File("target/test-classes/jarfile.jar").toURI().toURL(); // Retrieve using 'file:' - URL jarUrl = new URL("jar:" + url.toString() + "!/config/console.xml"); + URL jarUrl = new URL("jar:" + url + "!/config/console.xml"); long expected = getOpenFileDescriptorCount(); - UrlConnectionFactory.createConnection(jarUrl).getInputStream().close(); + urlConnectionFactory.openConnection(jarUrl).getInputStream().close(); assertEquals(expected, getOpenFileDescriptorCount()); // Retrieve using 'http:' jarUrl = new URL("jar:http://localhost:" + port + "/jarfile.jar!/config/console.xml"); final File tmpDir = new File(System.getProperty("java.io.tmpdir")); expected = tmpDir.list().length; - UrlConnectionFactory.createConnection(jarUrl).getInputStream().close(); + urlConnectionFactory.openConnection(jarUrl).getInputStream().close(); assertEquals(expected, tmpDir.list().length, "File descriptor leak"); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java index 0ed2262ec7d..cdd84316196 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java @@ -16,75 +16,51 @@ */ package org.apache.logging.log4j.core.net.ssl; +import java.security.KeyStore; + import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.apache.logging.log4j.test.junit.StatusLoggerLevel; import org.junit.jupiter.api.Test; -import java.security.KeyStore; - import static org.junit.jupiter.api.Assertions.*; @StatusLoggerLevel("OFF") public class KeyStoreConfigurationTest { - @SuppressWarnings("deprecation") - @Test - public void loadEmptyConfigurationDeprecated() { - assertThrows(StoreConfigurationException.class, - () -> new KeyStoreConfiguration(null, TestConstants.NULL_PWD, null, null)); - } - @Test public void loadEmptyConfiguration() { assertThrows(StoreConfigurationException.class, - () -> new KeyStoreConfiguration(null, new MemoryPasswordProvider(TestConstants.NULL_PWD), null, null)); - } - - @Test - public void loadNotEmptyConfigurationDeprecated() throws StoreConfigurationException { - @SuppressWarnings("deprecation") final KeyStoreConfiguration ksc = - new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), - TestConstants.KEYSTORE_TYPE, null); - final KeyStore ks = ksc.getKeyStore(); - assertNotNull(ks); + () -> KeyStoreConfiguration.builder().build()); } @Test public void loadNotEmptyConfiguration() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), - TestConstants.KEYSTORE_TYPE, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .setKeyStoreType(TestConstants.KEYSTORE_TYPE) + .build(); final KeyStore ks = ksc.getKeyStore(); assertNotNull(ks); } - @Test - public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws StoreConfigurationException { - @SuppressWarnings("deprecation") final KeyStoreConfiguration ksc = - new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), - TestConstants.KEYSTORE_TYPE, null); - final KeyStore ks = ksc.getKeyStore(); - final KeyStore ks2 = ksc.getKeyStore(); - assertSame(ks, ks2); - } - @Test public void returnTheSameKeyStoreAfterMultipleLoads() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), - TestConstants.KEYSTORE_TYPE, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .setKeyStoreType(TestConstants.KEYSTORE_TYPE) + .build(); final KeyStore ks = ksc.getKeyStore(); final KeyStore ks2 = ksc.getKeyStore(); assertSame(ks, ks2); } - @SuppressWarnings("deprecation") - @Test - public void wrongPasswordDeprecated() { - assertThrows(StoreConfigurationException.class, - () -> new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, "wrongPassword!", null, null)); - } - @Test public void wrongPassword() { - assertThrows(StoreConfigurationException.class, () -> new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - new MemoryPasswordProvider("wrongPassword!".toCharArray()), null, null)); + assertThrows(StoreConfigurationException.class, () -> + KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword("wrongPassword!".toCharArray()) + .build()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactoryTest.java index 27370e28be5..c3e360256af 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactoryTest.java @@ -18,8 +18,13 @@ import java.util.Properties; +import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.test.net.ssl.TestConstants; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.plugins.di.DI; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.util.PropertiesPropertySource; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.PropertySource; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -28,35 +33,38 @@ public class SslConfigurationFactoryTest { private static void addKeystoreConfiguration(Properties props) { - props.setProperty("log4j2.keyStoreLocation", TestConstants.KEYSTORE_FILE_RESOURCE); - props.setProperty("log4j2.keyStoreKeyStoreType", TestConstants.KEYSTORE_TYPE); + props.setProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_LOCATION, TestConstants.KEYSTORE_FILE_RESOURCE); + props.setProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_TYPE, TestConstants.KEYSTORE_TYPE); } private static void addTruststoreConfiguration(Properties props) { - props.setProperty("log4j2.trustStoreLocation", TestConstants.TRUSTSTORE_FILE_RESOURCE); - props.setProperty("log4j2.trustStoreKeyStoreType", TestConstants.TRUSTSTORE_TYPE); + props.setProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_LOCATION, TestConstants.TRUSTSTORE_FILE_RESOURCE); + props.setProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_KEY_STORE_TYPE, TestConstants.TRUSTSTORE_TYPE); } @Test public void testStaticConfiguration() { + final Injector injector = DI.createInjector(); + injector.init(); + final PropertyResolver resolver = injector.getInstance(PropertyResolver.class); final Properties props = new Properties(); - final PropertiesUtil util = new PropertiesUtil(props); + final PropertySource source = new PropertiesPropertySource(props); + resolver.addSource(source); + final SslConfigurationFactory factory = new SslConfigurationFactory(resolver); // No keystore and truststore -> no SslConfiguration - SslConfiguration sslConfiguration = SslConfigurationFactory.createSslConfiguration(util); + SslConfiguration sslConfiguration = factory.get(); assertNull(sslConfiguration); // Only keystore props.clear(); addKeystoreConfiguration(props); - util.reload(); - sslConfiguration = SslConfigurationFactory.createSslConfiguration(util); + sslConfiguration = factory.get(); assertNotNull(sslConfiguration); assertNotNull(sslConfiguration.getKeyStoreConfig()); assertNull(sslConfiguration.getTrustStoreConfig()); // Only truststore props.clear(); addTruststoreConfiguration(props); - util.reload(); - sslConfiguration = SslConfigurationFactory.createSslConfiguration(util); + sslConfiguration = factory.get(); assertNotNull(sslConfiguration); assertNull(sslConfiguration.getKeyStoreConfig()); assertNotNull(sslConfiguration.getTrustStoreConfig()); @@ -64,8 +72,7 @@ public void testStaticConfiguration() { props.clear(); addKeystoreConfiguration(props); addTruststoreConfiguration(props); - util.reload(); - sslConfiguration = SslConfigurationFactory.createSslConfiguration(util); + sslConfiguration = factory.get(); assertNotNull(sslConfiguration); assertNotNull(sslConfiguration.getKeyStoreConfig()); assertNotNull(sslConfiguration.getTrustStoreConfig()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java index f9f25fb9434..79704f86d41 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java @@ -20,7 +20,6 @@ import java.io.OutputStream; import java.net.ConnectException; import java.net.UnknownHostException; - import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -36,37 +35,29 @@ public class SslConfigurationTest { private static final String TLS_TEST_HOST = "login.yahoo.com"; private static final int TLS_TEST_PORT = 443; - @SuppressWarnings("deprecation") - public static SslConfiguration createTestSslConfigurationResourcesDeprecated() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE, - TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE, - TestConstants.TRUSTSTORE_PWD(), null, null); - return SslConfiguration.createSSLConfiguration(null, ksc, tsc); - } - public static SslConfiguration createTestSslConfigurationResources() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE, - new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE, - new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); - return SslConfiguration.createSSLConfiguration(null, ksc, tsc); - } - - @SuppressWarnings("deprecation") - public static SslConfiguration createTestSslConfigurationFilesDeprecated() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, - TestConstants.TRUSTSTORE_PWD(), null, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE_RESOURCE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .setKeyStoreType(TestConstants.KEYSTORE_TYPE) + .build(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE_RESOURCE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } public static SslConfiguration createTestSslConfigurationFiles() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, - new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder() + .setLocation(TestConstants.KEYSTORE_FILE) + .setPassword(TestConstants.KEYSTORE_PWD()) + .setKeyStoreType(TestConstants.KEYSTORE_TYPE) + .build(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } @@ -116,8 +107,7 @@ public void emptyConfigurationHasDefaultTrustStore() throws IOException { @Test public void connectionFailsWithoutValidServerCertificate() throws IOException, StoreConfigurationException { - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, - new MemoryPasswordProvider(TestConstants.NULL_PWD), null, null); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder().setLocation(TestConstants.TRUSTSTORE_FILE).build(); final SslConfiguration sc = SslConfiguration.createSSLConfiguration(null, null, tsc); final SSLSocketFactory factory = sc.getSslSocketFactory(); try { @@ -133,8 +123,7 @@ public void connectionFailsWithoutValidServerCertificate() throws IOException, S @Test public void loadKeyStoreWithoutPassword() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - new MemoryPasswordProvider(TestConstants.NULL_PWD), null, null); + final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder().setLocation(TestConstants.KEYSTORE_FILE).build(); final SslConfiguration sslConf = SslConfiguration.createSSLConfiguration(null, ksc, null); final SSLSocketFactory factory = sslConf.getSslSocketFactory(); assertNotNull(factory); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java index a62f91ad64f..37aebb83934 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java @@ -16,67 +16,48 @@ */ package org.apache.logging.log4j.core.net.ssl; +import java.security.KeyStore; + import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.apache.logging.log4j.test.junit.StatusLoggerLevel; import org.junit.jupiter.api.Test; -import java.security.KeyStore; - import static org.junit.jupiter.api.Assertions.*; @StatusLoggerLevel("OFF") public class TrustStoreConfigurationTest { - @SuppressWarnings("deprecation") - @Test - public void loadEmptyConfigurationDeprecated() { - assertThrows(StoreConfigurationException.class, () -> new TrustStoreConfiguration(null, TestConstants.NULL_PWD, null, null)); - } - @Test public void loadEmptyConfiguration() { - assertThrows(StoreConfigurationException.class, () -> new TrustStoreConfiguration(null, new MemoryPasswordProvider(TestConstants.NULL_PWD), null, null)); - } - - @Test - public void loadConfigurationDeprecated() throws StoreConfigurationException { - @SuppressWarnings("deprecation") final TrustStoreConfiguration ksc = - new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); - final KeyStore ks = ksc.getKeyStore(); - assertNotNull(ks); + assertThrows(StoreConfigurationException.class, () -> TrustStoreConfiguration.builder().build()); } @Test public void loadConfiguration() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); - final KeyStore ks = ksc.getKeyStore(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); + final KeyStore ks = tsc.getKeyStore(); assertNotNull(ks); } - @Test - public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws StoreConfigurationException { - @SuppressWarnings("deprecation") final TrustStoreConfiguration ksc = - new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); - final KeyStore ks = ksc.getKeyStore(); - final KeyStore ks2 = ksc.getKeyStore(); - assertSame(ks, ks2); - } - @Test public void returnTheSameKeyStoreAfterMultipleLoads() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); - final KeyStore ks = ksc.getKeyStore(); - final KeyStore ks2 = ksc.getKeyStore(); + final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword(TestConstants.TRUSTSTORE_PWD()) + .build(); + final KeyStore ks = tsc.getKeyStore(); + final KeyStore ks2 = tsc.getKeyStore(); assertSame(ks, ks2); } - @SuppressWarnings("deprecation") - @Test - public void wrongPasswordDeprecated() { - assertThrows(StoreConfigurationException.class, () -> new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, "wrongPassword!".toCharArray(), null, null)); - } - @Test public void wrongPassword() { - assertThrows(StoreConfigurationException.class, () -> new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider("wrongPassword!".toCharArray()), null, null)); + assertThrows(StoreConfigurationException.class, () -> + TrustStoreConfiguration.builder() + .setLocation(TestConstants.TRUSTSTORE_FILE) + .setPassword("wrongPassword!".toCharArray()) + .build()); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java index fdf6ca365e8..245e5e9f7f9 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedTimeZoneFormat; -import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.util.Strings; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +42,6 @@ public class DatePatternConverterTest { private static class MyLogEvent extends AbstractLogEvent { - private static final long serialVersionUID = 0; @Override public Instant getInstant() { @@ -90,7 +89,7 @@ public static Collection data() { } public DatePatternConverterTest(final Boolean threadLocalEnabled) { - Constants.setThreadLocalsEnabled(threadLocalEnabled); + System.setProperty(LoggingSystemProperties.SYSTEM_THREAD_LOCALS_ENABLED, threadLocalEnabled.toString()); } private static Date date(final int year, final int month, final int date) { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverterTest.java index e996241f209..45064379635 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverterTest.java @@ -21,7 +21,6 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; @@ -31,11 +30,11 @@ public class EncodingPatternConverterTest { @Test public void testReplacement() { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(EncodingPatternConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Test \r\n
this
&
that
")) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final String[] options = new String[]{"%msg"}; @@ -50,11 +49,11 @@ public void testReplacement() { @Test public void testJsonEscaping() { - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName(getClass().getName()) .setLevel(Level.DEBUG) .setMessage(new SimpleMessage("This string contains \"quotes\" and \\ backslash and \u001F control and\nnewline")) - .build(); + .get(); final String expected = "This string contains \\\"quotes\\\" and \\\\ backslash and \\u001F control and\\nnewline"; final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); @@ -69,11 +68,11 @@ public void testJsonEscaping() { @Test public void testCrlfEscaping() { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(EncodingPatternConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Test \r\n
this\r
& \n
that
")) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final String[] options = new String[]{"%msg", "CRLF"}; @@ -88,11 +87,11 @@ public void testCrlfEscaping() { @Test public void testXmlEscaping() { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(EncodingPatternConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Test \r\n
this
&
that
")) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final String[] options = new String[]{"%msg", "XML"}; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverterTest.java index eda57d257d7..3bf2b49d075 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverterTest.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -26,8 +25,7 @@ public class EndOfBatchPatternConverterTest { @Test public void testConverterTrue() { - final LogEvent event = Log4jLogEvent.newBuilder() - .setEndOfBatch(true).build(); + final LogEvent event = LogEvent.builder().endOfBatch(true).get(); final StringBuilder sb = new StringBuilder(); final LogEventPatternConverter converter = EndOfBatchPatternConverter.newInstance(null); converter.format(event, sb); @@ -36,8 +34,7 @@ public void testConverterTrue() { @Test public void testConverterFalse() { - final LogEvent event = Log4jLogEvent.newBuilder() - .build(); + final LogEvent event = LogEvent.builder().get(); final StringBuilder sb = new StringBuilder(); final LogEventPatternConverter converter = EndOfBatchPatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsIgnoreCaseReplacementConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsIgnoreCaseReplacementConverterTest.java index fa4ae878cbe..dff4e2d475b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsIgnoreCaseReplacementConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsIgnoreCaseReplacementConverterTest.java @@ -19,12 +19,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class EqualsIgnoreCaseReplacementConverterTest { @@ -44,11 +44,11 @@ public void testLoggerNameReplacement() { } private void testReplacement(final String tag, final String expectedValue) { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(EqualsIgnoreCaseReplacementConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("This is a test")) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final String[] options = new String[] { "aaa[" + tag + "]zzz", "AAA[]ZZZ", expectedValue }; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java index 35bee32d102..66598a37d76 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java @@ -19,12 +19,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class EqualsReplacementConverterTest { @@ -56,11 +56,11 @@ private void testReplacement(final String tag, final String expectedValue) { } private void testReplacement(final String expectedValue, final String[] options) { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(EqualsReplacementConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage(TEST_MESSAGE)) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final EqualsReplacementConverter converter = EqualsReplacementConverter.newInstance(ctx.getConfiguration(), @@ -92,11 +92,11 @@ public void testParseSubstitutionWithWhiteSpaces() { } private void testParseSubstitution(final String substitution, final String expected) { - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName(EqualsReplacementConverterTest.class.getName()) .setLevel(Level.DEBUG) .setMessage(new SimpleMessage(TEST_MESSAGE)) - .build(); + .get(); final LoggerContext ctx = LoggerContext.getContext(); final EqualsReplacementConverter converter = EqualsReplacementConverter.newInstance(ctx.getConfiguration(), new String[]{"[%marker]", "[]", substitution}); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java index a204894326d..112ab7090e1 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java @@ -23,9 +23,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; @@ -42,12 +40,13 @@ public void testSuffixFromNormalPattern() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent) + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -61,12 +60,13 @@ public void testSuffix() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent) + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -80,39 +80,19 @@ public void testSuffixWillIgnoreThrowablePattern() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent) + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); assertFalse(result.contains("inner suffix"), "Has unexpected suffix"); } - @Test - public void testDeserializedLogEventWithThrowableProxyButNoThrowable() { - final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, null); - final Throwable originalThrowable = new Exception("something bad happened"); - final ThrowableProxy throwableProxy = new ThrowableProxy(originalThrowable); - final Throwable deserializedThrowable = null; - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName("testLogger") // - .setLoggerFqcn(this.getClass().getName()) // - .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("")) // - .setThrown(deserializedThrowable) // - .setThrownProxy(throwableProxy) // - .setTimeMillis(0).build(); - final StringBuilder sb = new StringBuilder(); - converter.format(event, sb); - final String result = sb.toString(); - assertTrue(result.contains(originalThrowable.getMessage()), result); - assertTrue(result.contains(originalThrowable.getStackTrace()[0].getMethodName()), result); - } - @Test public void testFiltering() { final String packages = "filters(org.junit, org.apache.maven, sun.reflect, java.lang.reflect)"; @@ -120,12 +100,13 @@ public void testFiltering() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent) + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -137,12 +118,13 @@ public void testFull() { final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null, null); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent) + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final StringWriter sw = new StringWriter(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/HighlightConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/HighlightConverterTest.java index c62889543aa..97c206711a8 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/HighlightConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/HighlightConverterTest.java @@ -1,4 +1,4 @@ -package org.apache.logging.log4j.core.pattern;/* +/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -14,10 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ +package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; @@ -34,8 +34,8 @@ public void testAnsiEmpty() { final HighlightConverter converter = HighlightConverter.newInstance(null, options); assertNotNull(converter); - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( - new SimpleMessage("message in a bottle")).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( + new SimpleMessage("message in a bottle")).get(); final StringBuilder buffer = new StringBuilder(); converter.format(event, buffer); assertEquals("", buffer.toString()); @@ -47,8 +47,8 @@ public void testAnsiNonEmpty() { final HighlightConverter converter = HighlightConverter.newInstance(null, options); assertNotNull(converter); - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( - new SimpleMessage("message in a bottle")).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( + new SimpleMessage("message in a bottle")).get(); final StringBuilder buffer = new StringBuilder(); converter.format(event, buffer); assertEquals("\u001B[32mINFO : message in a bottle\u001B[m", buffer.toString()); @@ -114,8 +114,8 @@ public void testNoAnsiEmpty() { final HighlightConverter converter = HighlightConverter.newInstance(null, options); assertNotNull(converter); - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( - new SimpleMessage("message in a bottle")).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( + new SimpleMessage("message in a bottle")).get(); final StringBuilder buffer = new StringBuilder(); converter.format(event, buffer); assertEquals("", buffer.toString()); @@ -127,8 +127,8 @@ public void testNoAnsiNonEmpty() { final HighlightConverter converter = HighlightConverter.newInstance(null, options); assertNotNull(converter); - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( - new SimpleMessage("message in a bottle")).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.INFO).setLoggerName("a.b.c").setMessage( + new SimpleMessage("message in a bottle")).get(); final StringBuilder buffer = new StringBuilder(); converter.format(event, buffer); assertEquals("INFO : message in a bottle", buffer.toString()); @@ -137,9 +137,9 @@ public void testNoAnsiNonEmpty() { private CharSequence toFormattedCharSeq(final HighlightConverter converter, final Level level) { final StringBuilder sb= new StringBuilder(); - converter.format(Log4jLogEvent.newBuilder() + converter.format(LogEvent.builder() .setLevel(level) - .build(), sb); + .get(), sb); return sb; } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LevelPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LevelPatternConverterTest.java index bde85e12cb5..4f5d5dfc343 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LevelPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LevelPatternConverterTest.java @@ -18,21 +18,20 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LevelPatternConverterTest { private void testLevelLength(final int length, final String debug, final String warn) { final Message msg = new SimpleMessage("Hello"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); LevelPatternConverter converter = LevelPatternConverter.newInstance(null); converter.format(event, sb); @@ -42,10 +41,10 @@ private void testLevelLength(final int length, final String debug, final String sb.setLength(0); converter.format(event, sb); assertEquals(debug, sb.toString()); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.WARN) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb.setLength(0); converter.format(event, sb); assertEquals(warn, sb.toString()); @@ -74,10 +73,10 @@ public void testLevelLength5() { @Test public void testLevelLowerCase() { final Message msg = new SimpleMessage("Hello"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); LevelPatternConverter converter = LevelPatternConverter.newInstance(null); converter.format(event, sb); @@ -87,10 +86,10 @@ public void testLevelLowerCase() { sb.setLength(0); converter.format(event, sb); assertEquals("debug", sb.toString()); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.WARN) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb.setLength(0); converter.format(event, sb); assertEquals("warn", sb.toString()); @@ -99,10 +98,10 @@ public void testLevelLowerCase() { @Test public void testLevelMap() { final Message msg = new SimpleMessage("Hello"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); LevelPatternConverter converter = LevelPatternConverter.newInstance(null); converter.format(event, sb); @@ -112,10 +111,10 @@ public void testLevelMap() { sb.setLength(0); converter.format(event, sb); assertEquals("Debug", sb.toString()); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.WARN) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb.setLength(0); converter.format(event, sb); assertEquals("Warning", sb.toString()); @@ -124,10 +123,10 @@ public void testLevelMap() { @Test public void testLevelMapWithLength() { final Message msg = new SimpleMessage("Hello"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); LevelPatternConverter converter = LevelPatternConverter.newInstance(null); converter.format(event, sb); @@ -137,10 +136,10 @@ public void testLevelMapWithLength() { sb.setLength(0); converter.format(event, sb); assertEquals("DE", sb.toString()); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.WARN) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb.setLength(0); converter.format(event, sb); assertEquals("Warning", sb.toString()); @@ -149,10 +148,10 @@ public void testLevelMapWithLength() { @Test public void testLevelMapWithLengthAndLowerCase() { final Message msg = new SimpleMessage("Hello"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); LevelPatternConverter converter = LevelPatternConverter.newInstance(null); converter.format(event, sb); @@ -162,10 +161,10 @@ public void testLevelMapWithLengthAndLowerCase() { sb.setLength(0); converter.format(event, sb); assertEquals("de", sb.toString()); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.WARN) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb.setLength(0); converter.format(event, sb); assertEquals("Warning", sb.toString()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverterTest.java index a87679d5e7e..df3438b6a60 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverterTest.java @@ -17,10 +17,9 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LoggerFqcnPatternConverterTest { @@ -28,7 +27,7 @@ public class LoggerFqcnPatternConverterTest { @Test public void testConverter() { - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerFqcn(FQCN).build(); final StringBuilder sb = new StringBuilder(); final LogEventPatternConverter converter = LoggerFqcnPatternConverter.newInstance(null); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MapPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MapPatternConverterTest.java index 735e0ce847f..bcee956dd8f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MapPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MapPatternConverterTest.java @@ -18,12 +18,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class MapPatternConverterTest { @@ -35,7 +35,7 @@ public void testConverter() { msg.put("verb", "love"); msg.put("object", "Log4j"); final MapPatternConverter converter = MapPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // @@ -61,7 +61,7 @@ public void testConverterWithKey() { msg.put("verb", "love"); msg.put("object", "Log4j"); final MapPatternConverter converter = MapPatternConverter.newInstance(new String[] {"object"}); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // @@ -81,7 +81,7 @@ public void testConverterWithJavaFormat() { msg.put("verb", "love"); msg.put("object", "Log4j"); final MapPatternConverter converter = MapPatternConverter.newInstance(null, MapMessage.MapFormat.JAVA); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerPatternConverterTest.java index da06f55ba97..5d45296bc8e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerPatternConverterTest.java @@ -20,12 +20,11 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.StructuredDataMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests {@link MarkerPatternConverter}. @@ -37,8 +36,8 @@ public void testLookup() { final Message msg = new StructuredDataMessage("Test", "This is a test", "Audit"); final Marker eventMarker = MarkerManager.getMarker("EVENT"); final Marker auditMarker = MarkerManager.getMarker("AUDIT").setParents(eventMarker); - final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("MyLogger").setMarker(auditMarker) - .setLevel(Level.DEBUG).setMessage(msg).build(); + final LogEvent event = LogEvent.builder().setLoggerName("MyLogger").setMarker(auditMarker) + .setLevel(Level.DEBUG).setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); final MarkerPatternConverter converter = MarkerPatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerSimpleNamePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerSimpleNamePatternConverterTest.java index 88bebcf4b47..3923d4226c4 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerSimpleNamePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MarkerSimpleNamePatternConverterTest.java @@ -20,12 +20,11 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.StructuredDataMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests {@link MarkerSimpleNamePatternConverter}. @@ -37,8 +36,8 @@ public void testLookup() { final Message msg = new StructuredDataMessage("Test", "This is a test", "Audit"); final Marker eventMarker = MarkerManager.getMarker("EVENT"); final Marker auditMarker = MarkerManager.getMarker("AUDIT").setParents(eventMarker); - final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("MyLogger").setMarker(auditMarker) - .setLevel(Level.DEBUG).setMessage(msg).build(); + final LogEvent event = LogEvent.builder().setLoggerName("MyLogger").setMarker(auditMarker) + .setLevel(Level.DEBUG).setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); final MarkerSimpleNamePatternConverter converter = MarkerSimpleNamePatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MaxLengthConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MaxLengthConverterTest.java index a41a5feab01..3ac1b4fd2bd 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MaxLengthConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MaxLengthConverterTest.java @@ -14,17 +14,15 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MaxLengthConverterTest { @@ -33,11 +31,11 @@ public class MaxLengthConverterTest { @Test public void testUnderMaxLength() { final Message message = new SimpleMessage("0123456789"); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("MyLogger") .setLevel(Level.DEBUG) .setMessage(message) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("0123456789", sb.toString()); @@ -46,11 +44,11 @@ public void testUnderMaxLength() { @Test public void testOverMaxLength() { final Message message = new SimpleMessage("01234567890123456789"); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("MyLogger") .setLevel(Level.DEBUG) .setMessage(message) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("0123456789", sb.toString()); @@ -59,11 +57,11 @@ public void testOverMaxLength() { @Test public void testOverMaxLength21WithEllipsis() { final Message message = new SimpleMessage("012345678901234567890123456789"); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName("MyLogger") .setLevel(Level.DEBUG) .setMessage(message) - .build(); + .get(); final StringBuilder sb = new StringBuilder(); MaxLengthConverter.newInstance(null, new String[]{"%m", "21"}).format(event, sb); assertEquals("012345678901234567890...", sb.toString()); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MdcPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MdcPatternConverterTest.java index fd87a7f9b03..34694aac37f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MdcPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MdcPatternConverterTest.java @@ -19,14 +19,13 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.test.junit.UsingThreadContextMap; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.test.junit.UsingThreadContextMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; @UsingThreadContextMap public class MdcPatternConverterTest { @@ -42,11 +41,11 @@ public void setup() { public void testConverter() { final Message msg = new SimpleMessage("Hello"); final MdcPatternConverter converter = MdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -58,11 +57,11 @@ public void testConverter() { public void testConverterWithExistingData() { final Message msg = new SimpleMessage("Hello"); final MdcPatternConverter converter = MdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); sb.append("prefix "); converter.format(event, sb); @@ -76,11 +75,11 @@ public void testConverterFullEmpty() { ThreadContext.clearMap(); final Message msg = new SimpleMessage("Hello"); final MdcPatternConverter converter = MdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -94,11 +93,11 @@ public void testConverterFullSingle() { ThreadContext.put("foo", "bar"); final Message msg = new SimpleMessage("Hello"); final MdcPatternConverter converter = MdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -111,11 +110,11 @@ public void testConverterWithKey() { final Message msg = new SimpleMessage("Hello"); final String [] options = new String[] {"object"}; final MdcPatternConverter converter = MdcPatternConverter.newInstance(options); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -128,11 +127,11 @@ public void testConverterWithKeys() { final Message msg = new SimpleMessage("Hello"); final String [] options = new String[] {"object, subject"}; final MdcPatternConverter converter = MdcPatternConverter.newInstance(options); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -145,11 +144,11 @@ public void testConverterWithKeysAndPrefix() { final Message msg = new SimpleMessage("Hello"); final String [] options = new String[] {"object, subject"}; final MdcPatternConverter converter = MdcPatternConverter.newInstance(options); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); sb.append("prefix "); converter.format(event, sb); @@ -163,11 +162,11 @@ public void testConverterWithKeysSinglePresent() { final Message msg = new SimpleMessage("Hello"); final String [] options = new String[] {"object, notpresent"}; final MdcPatternConverter converter = MdcPatternConverter.newInstance(options); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -181,11 +180,11 @@ public void testConverterWithKeysNonePresent() { final Message msg = new SimpleMessage("Hello"); final String [] options = new String[] {"object, subject"}; final MdcPatternConverter converter = MdcPatternConverter.newInstance(options); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -194,4 +193,3 @@ public void testConverterWithKeysNonePresent() { } } - diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessagePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessagePatternConverterTest.java index 30be131f7df..475af47571e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessagePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessagePatternConverterTest.java @@ -21,8 +21,6 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.SimpleMessage; @@ -30,7 +28,7 @@ import org.apache.logging.log4j.message.StructuredDataMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MessagePatternConverterTest { @@ -38,25 +36,25 @@ public class MessagePatternConverterTest { public void testPattern() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, null); Message msg = new SimpleMessage("Hello!"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("Hello!", sb.toString(), "Unexpected result"); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(null).build(); + .setMessage(null).get(); sb = new StringBuilder(); converter.format(event, sb); assertEquals(0, sb.length(), "Incorrect length: " + sb); msg = new SimpleMessage(null); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb = new StringBuilder(); converter.format(event, sb); assertEquals(4, sb.length(), "Incorrect length: " + sb); @@ -66,10 +64,10 @@ public void testPattern() { public void testPatternAndParameterizedMessageDateLookup() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, null); final Message msg = new ParameterizedMessage("${date:now:buhu}"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("${date:now:buhu}", sb.toString(), "Unexpected result"); @@ -82,10 +80,10 @@ public void testDefaultDisabledLookup() { .build(true); final MessagePatternConverter converter = MessagePatternConverter.newInstance(config, null); final Message msg = new ParameterizedMessage("${foo}"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("${foo}", sb.toString(), "Unexpected result"); @@ -99,10 +97,10 @@ public void testDisabledLookup() { final MessagePatternConverter converter = MessagePatternConverter.newInstance( config, new String[] {"nolookups"}); final Message msg = new ParameterizedMessage("${foo}"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("${foo}", sb.toString(), "Expected the raw pattern string without lookup"); @@ -116,10 +114,10 @@ public void testLookup() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(config, new String[] {"lookups"}); final Message msg = new ParameterizedMessage("${foo}"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("${foo}", sb.toString(), "Unexpected result"); @@ -130,25 +128,25 @@ public void testPatternWithConfiguration() { final Configuration config = new DefaultConfiguration(); final MessagePatternConverter converter = MessagePatternConverter.newInstance(config, null); Message msg = new SimpleMessage("Hello!"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("Hello!", sb.toString(), "Unexpected result"); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(null).build(); + .setMessage(null).get(); sb = new StringBuilder(); converter.format(event, sb); assertEquals(0, sb.length(), "Incorrect length: " + sb); msg = new SimpleMessage(null); - event = Log4jLogEvent.newBuilder() // + event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); sb = new StringBuilder(); converter.format(event, sb); assertEquals(4, sb.length(), "Incorrect length: " + sb); @@ -159,10 +157,10 @@ public void testMapMessageFormatJson() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, new String[]{"json"}); Message msg = new StringMapMessage() .with("key", "val"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("{\"key\":\"val\"}", sb.toString(), "Unexpected result"); @@ -173,10 +171,10 @@ public void testMapMessageFormatXml() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, new String[]{"xml"}); Message msg = new StringMapMessage() .with("key", "val"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("\n val\n", sb.toString(), "Unexpected result"); @@ -187,10 +185,10 @@ public void testMapMessageFormatDefault() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, null); Message msg = new StringMapMessage() .with("key", "val"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("key=\"val\"", sb.toString(), "Unexpected result"); @@ -201,10 +199,10 @@ public void testStructuredDataFormatFull() { final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, new String[]{"FULL"}); Message msg = new StructuredDataMessage("id", "message", "type") .with("key", "val"); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(msg).build(); + .setMessage(msg).get(); StringBuilder sb = new StringBuilder(); converter.format(event, sb); assertEquals("type [id key=\"val\"] message", sb.toString(), "Unexpected result"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java index c4a0238b564..222da2b1ee2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java @@ -17,17 +17,16 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class NanoTimePatternConverterTest { @Test public void testConverterAppendsLogEventNanoTimeToStringBuilder() { - final LogEvent event = Log4jLogEvent.newBuilder() // - .setNanoTime(1234567).build(); + final LogEvent event = LogEvent.builder() // + .setNanoTime(1234567).get(); final StringBuilder sb = new StringBuilder(); final NanoTimePatternConverter converter = NanoTimePatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NdcPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NdcPatternConverterTest.java index 1218bb0ff53..94f387accf0 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NdcPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/NdcPatternConverterTest.java @@ -19,13 +19,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.test.junit.UsingThreadContextStack; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.test.junit.UsingThreadContextStack; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; @UsingThreadContextStack public class NdcPatternConverterTest { @@ -59,11 +58,11 @@ public void test3() { private void testConverter(final String expected) { final Message msg = new SimpleMessage("Hello"); final NdcPatternConverter converter = NdcPatternConverter.newInstance(null); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // .setMessage(msg) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String str = sb.toString(); @@ -71,4 +70,3 @@ private void testConverter(final String expected) { } } - diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java index c5d0f78b163..a3c0bac662b 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java @@ -26,12 +26,11 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.NullConfiguration; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; import org.apache.logging.log4j.core.time.SystemNanoClock; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.BeforeEach; @@ -94,11 +93,11 @@ public void defaultPattern() { public void testCustomPattern() { final List formatters = parser.parse(customPattern); assertNotNull(formatters); - final StringMap mdc = ContextDataFactory.createContextData(); + final StringMap mdc = new SortedArrayStringMap(); mdc.putValue("loginId", "Fred"); final Throwable t = new Throwable(); final StackTraceElement[] elements = t.getStackTrace(); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // + final var event = LogEvent.builder() // .setLoggerName("org.apache.logging.log4j.PatternParserTest") // .setMarker(MarkerManager.getMarker("TEST")) // .setLoggerFqcn(Logger.class.getName()) // @@ -107,7 +106,7 @@ public void testCustomPattern() { .setContextData(mdc) // .setThreadName("Thread1") // .setSource(elements[0]) - .setTimeMillis(System.currentTimeMillis()).build(); + .setTimeMillis(System.currentTimeMillis()).get(); final StringBuilder buf = new StringBuilder(); for (final PatternFormatter formatter : formatters) { formatter.format(event, buf); @@ -121,7 +120,7 @@ public void testCustomPattern() { public void testPatternTruncateFromBeginning() { final List formatters = parser.parse(patternTruncateFromBeginning); assertNotNull(formatters); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("org.apache.logging.log4j.PatternParserTest") // .setLoggerFqcn(Logger.class.getName()) // .setLevel(Level.INFO) // @@ -142,7 +141,7 @@ public void testPatternTruncateFromBeginning() { public void testPatternTruncateFromEnd() { final List formatters = parser.parse(patternTruncateFromEnd); assertNotNull(formatters); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("org.apache.logging.log4j.PatternParserTest") // .setLoggerFqcn(Logger.class.getName()) // .setLevel(Level.INFO) // @@ -170,7 +169,7 @@ public void testBadPattern() { assertNotNull(formatters); final Throwable t = new Throwable(); final StackTraceElement[] elements = t.getStackTrace(); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("a.b.c") // .setLoggerFqcn(Logger.class.getName()) // .setLevel(Level.INFO) // @@ -205,7 +204,7 @@ private void testNestedPatternHighlight(final Level level, final String expected assertNotNull(formatters); final Throwable t = new Throwable(); t.getStackTrace(); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("org.apache.logging.log4j.PatternParserTest") // .setMarker(MarkerManager.getMarker("TEST")) // .setLoggerFqcn(Logger.class.getName()) // @@ -341,9 +340,9 @@ public void testDeeplyNestedPattern() { assertNotNull(formatters); assertEquals(1, formatters.size()); - final StringMap mdc = ContextDataFactory.createContextData(); + final StringMap mdc = new SortedArrayStringMap(); mdc.putValue("var", "1234"); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // + final var event = LogEvent.builder() // .setContextData(mdc).build(); final StringBuilder buf = new StringBuilder(); formatters.get(0).format(event, buf); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementConverterTest.java index b9ffe3fec0f..bd5966b4ae5 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementConverterTest.java @@ -20,23 +20,23 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class RegexReplacementConverterTest { @Test public void testReplacement() { ThreadContext.put("MyKey", "Apache"); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(RegexReplacementConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("This is a test")) // - .build(); + .get(); final StringBuilder sb = new StringBuilder(); final LoggerContext ctx = LoggerContext.getContext(); final String[] options = new String[] { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverterTest.java index ee1ed34ac21..a48f72cb264 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverterTest.java @@ -18,7 +18,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; @@ -39,10 +38,10 @@ public void repeat() { converter.format(null, sb); assertEquals(expected, sb.toString()); sb.setLength(0); - LogEvent event = Log4jLogEvent.newBuilder() // + LogEvent event = LogEvent.builder() // .setLoggerName("MyLogger") // .setLevel(Level.DEBUG) // - .setMessage(new SimpleMessage("Hello")).build(); + .setMessage(new SimpleMessage("Hello")).get(); converter.format(event, sb); assertEquals(expected, sb.toString()); } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java index 846a460429e..fedd7d5d5e8 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverterTest.java @@ -19,11 +19,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RootThrowablePatternConverterTest { @@ -34,12 +34,12 @@ public void testSuffix() { final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -54,12 +54,12 @@ public void testSuffixFromNormalPattern() { final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -73,12 +73,12 @@ public void testSuffixWillIgnoreThrowablePattern() { final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -90,12 +90,12 @@ public void testFull1() { final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null, null); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -122,12 +122,12 @@ public void testFull2() { } catch (final IllegalArgumentException e) { parent = e; } - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java index fefd76f6692..84320957933 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java @@ -30,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.*; -@SetSystemProperty(key = Log4jProperties.JANSI_DISABLED, value = "false") +@SetSystemProperty(key = Log4jProperties.JANSI_ENABLED, value = "true") public class StyleConverterTest { private static final String EXPECTED = diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadIdPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadIdPatternConverterTest.java index 883cf71637f..f64fdf4ebc0 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadIdPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadIdPatternConverterTest.java @@ -17,17 +17,16 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ThreadIdPatternConverterTest { @Test public void testConverterAppendsLogEventNanoTimeToStringBuilder() { - final LogEvent event = Log4jLogEvent.newBuilder() // - .setThreadId(1).build(); + final LogEvent event = LogEvent.builder() // + .setThreadId(1).get(); final StringBuilder sb = new StringBuilder(); final ThreadIdPatternConverter converter = ThreadIdPatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadNamePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadNamePatternConverterTest.java index 2458b6befd4..1d286eb5902 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadNamePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadNamePatternConverterTest.java @@ -17,17 +17,16 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ThreadNamePatternConverterTest { @Test public void testConverterAppendsLogEventNanoTimeToStringBuilder() { - final LogEvent event = Log4jLogEvent.newBuilder() // - .setThreadName("Hello-1").build(); + final LogEvent event = LogEvent.builder() // + .setThreadName("Hello-1").get(); final StringBuilder sb = new StringBuilder(); final ThreadNamePatternConverter converter = ThreadNamePatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadPriorityPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadPriorityPatternConverterTest.java index 82b6cd7836a..dd197de1a6e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadPriorityPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThreadPriorityPatternConverterTest.java @@ -17,17 +17,16 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ThreadPriorityPatternConverterTest { @Test public void testConverterAppendsLogEventNanoTimeToStringBuilder() { - final LogEvent event = Log4jLogEvent.newBuilder() // - .setThreadPriority(1).build(); + final LogEvent event = LogEvent.builder() // + .setThreadPriority(1).get(); final StringBuilder sb = new StringBuilder(); final ThreadPriorityPatternConverter converter = ThreadPriorityPatternConverter.newInstance(null); converter.format(event, sb); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java index cc52994ca28..e54a5b14d75 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverterTest.java @@ -18,7 +18,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; @@ -70,12 +69,12 @@ public void testFull() { } catch (final IllegalArgumentException e) { parent = e; } - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -91,12 +90,12 @@ public void testShortClassName() { final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -109,12 +108,12 @@ public void testShortFileName() { final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -130,12 +129,12 @@ public void testShortLineNumber() { final StackTraceElement top = parent.getStackTrace()[0]; final int expectedLineNumber = top.getLineNumber(); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -147,12 +146,12 @@ public void testShortLocalizedMessage() { final String[] options = { "short.localizedMessage" }; final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable parent = new LocalizedException(); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -165,12 +164,12 @@ public void testShortMessage() { final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -183,12 +182,12 @@ public void testShortMethodName() { final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -209,12 +208,12 @@ public void testFullWithSuffix() { } catch (final IllegalArgumentException e) { parent = e; } - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); @@ -229,12 +228,12 @@ public void testShortOptionWithSuffix() { final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(null, options); final Throwable cause = new NullPointerException("null pointer"); final Throwable parent = new IllegalArgumentException("IllegalArgument", cause); - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName("testLogger") // .setLoggerFqcn(this.getClass().getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("test exception")) // - .setThrown(parent).build(); + .setThrown(parent).get(); final StringBuilder sb = new StringBuilder(); converter.format(event, sb); final String result = sb.toString(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java index 34a8a137f26..0083f33d1a3 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java @@ -19,12 +19,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class VariablesNotEmptyReplacementConverterTest { @@ -59,7 +59,7 @@ public void testLoggerNameReplacement() { } private void testReplacement(final String tag, final String expectedValue) { - final LogEvent event = Log4jLogEvent.newBuilder() // + final LogEvent event = LogEvent.builder() // .setLoggerName(VariablesNotEmptyReplacementConverterTest.class.getName()) // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("This is a test")) // diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java index 93091019b69..4dd5f95b1c1 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.util; +import java.util.Collection; +import java.util.concurrent.ConcurrentLinkedQueue; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; @@ -24,16 +27,16 @@ import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.SingletonFactory; +import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.status.StatusLogger; import org.junit.jupiter.api.Test; - -import java.util.Collection; -import java.util.concurrent.ConcurrentLinkedQueue; +import org.junitpioneer.jupiter.SetSystemProperty; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertTrue; +@SetSystemProperty(key = LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP, value = "false") public class ShutdownCallbackRegistryTest { @SingletonFactory diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java index cd73ef6d60e..3345fcb3022 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java @@ -37,7 +37,7 @@ import org.apache.logging.log4j.core.test.net.ssl.TestConstants; import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; import org.apache.logging.log4j.test.junit.StatusLoggerRule; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.Constants; import org.junit.Assume; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -47,11 +47,7 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule; import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.removeStub; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -66,7 +62,7 @@ public class WatchHttpTest { private static FastDateFormat formatter; private static final String XML = "application/xml"; - private static final boolean IS_WINDOWS = PropertiesUtil.getProperties().isOsWindows(); + private static final boolean IS_WINDOWS = Constants.isWindows(); @BeforeClass public static void beforeClass() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java index c3aea238c19..1eb3f9c73c0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java @@ -37,16 +37,7 @@ public class AbstractLifeCycle implements LifeCycle { */ protected static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger(); - /** - * Gets the status logger. - * - * @return the status logger. - */ - protected static org.apache.logging.log4j.Logger getStatusLogger() { - return LOGGER; - } - - private volatile LifeCycle.State state = LifeCycle.State.INITIALIZED; + private volatile LifeCycle.State state = State.INITIALIZED; protected boolean equalsImpl(final Object obj) { if (this == obj) { @@ -77,28 +68,6 @@ protected int hashCodeImpl() { return result; } - public boolean isInitialized() { - return this.state == LifeCycle.State.INITIALIZED; - } - - @Override - public boolean isStarted() { - return this.state == LifeCycle.State.STARTED; - } - - public boolean isStarting() { - return this.state == LifeCycle.State.STARTING; - } - - @Override - public boolean isStopped() { - return this.state == LifeCycle.State.STOPPED; - } - - public boolean isStopping() { - return this.state == LifeCycle.State.STOPPING; - } - protected void setStarted() { this.setState(LifeCycle.State.STARTED); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java index 35cbc94c65c..e4e430517aa 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java @@ -20,7 +20,6 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.message.Message; @@ -32,8 +31,6 @@ */ public abstract class AbstractLogEvent implements LogEvent { - private static final long serialVersionUID = 1L; - private volatile MutableInstant instant; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Appender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Appender.java index 7ca57426b9e..b074f029a41 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Appender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Appender.java @@ -16,8 +16,6 @@ */ package org.apache.logging.log4j.core; -import java.io.Serializable; - /** * Appends {@link LogEvent}s. An Appender can contain a {@link Layout} if applicable as well * as an {@link ErrorHandler}. Typical Appender implementations coordinate with an @@ -43,7 +41,7 @@ public interface Appender extends LifeCycle { * @since 2.6 */ String ELEMENT_TYPE = "appender"; - + /** * Empty array. */ @@ -71,7 +69,7 @@ public interface Appender extends LifeCycle { * * @return the Layout for this Appender or {@code null} if none is configured. */ - Layout getLayout(); + Layout getLayout(); /** * Some Appenders need to propagate exceptions back to the application. When {@code ignoreExceptions} is diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/ContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ContextDataInjector.java index 39da73a9198..ee7b7ae81cf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/ContextDataInjector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ContextDataInjector.java @@ -16,15 +16,14 @@ */ package org.apache.logging.log4j.core; +import java.util.List; + import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringMap; -import java.util.List; - /** * Responsible for initializing the context data of LogEvents. Context data is data that is set by the application to be * included in all subsequent log events. @@ -35,11 +34,12 @@ *

* In some asynchronous models, work may be delegated to several threads, while conceptually this work shares the same * context. In such models, storing context data in {@code ThreadLocal} variables is not convenient or desirable. - * Users can configure the {@code ContextDataInjectorFactory} to provide custom {@code ContextDataInjector} objects, + * Users can configure the {@code Supplier<ContextDataInjector>} binding to provide custom + * {@code ContextDataInjector} objects, * in order to initialize log events with context data from any arbitrary context. *

- * When providing a custom {@code ContextDataInjector}, be aware that the {@code ContextDataInjectorFactory} may be - * invoked multiple times and the various components in Log4j that need access to context data may each have their own + * When providing a custom {@code ContextDataInjector}, be aware that the instance may be created + * multiple times and the various components in Log4j that need access to context data may each have their own * instance of {@code ContextDataInjector}. * This includes the object(s) that populate log events, but also various lookups and filters that look at * context data to determine whether an event should be logged. @@ -50,7 +50,6 @@ * * @see StringMap * @see ReadOnlyStringMap - * @see ContextDataInjectorFactory * @see org.apache.logging.log4j.ThreadContext * @see ThreadContextDataInjector * @since 2.7 diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Core.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Core.java index dca48ec14cb..05709644252 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Core.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Core.java @@ -23,9 +23,6 @@ public class Core { - @Deprecated - public static final String CATEGORY_NAME = Node.CORE_NAMESPACE; - public static final Key PLUGIN_NAMESPACE_KEY = new @Namespace(Node.CORE_NAMESPACE) Key<>() {}; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ExtendedStackTraceElement.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/ExtendedStackTraceElement.java index 377d0e61842..be24120cf8a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedStackTraceElement.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ExtendedStackTraceElement.java @@ -14,10 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.impl; +package org.apache.logging.log4j.core; import java.io.Serializable; +import org.apache.logging.log4j.core.impl.ExtendedClassInfo; import org.apache.logging.log4j.core.pattern.PlainTextRenderer; import org.apache.logging.log4j.core.pattern.TextRenderer; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java index d63159687a5..1303340c0d4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core; -import java.io.Serializable; import java.util.Map; import org.apache.logging.log4j.core.layout.ByteBufferDestination; @@ -30,8 +29,6 @@ *

  • * {@code byte[]}
  • *
  • - * an implementer of {@linkplain Serializable}, like {@code byte[]}
  • - *
  • * {@linkplain String}
  • *
  • * {@linkplain LogEvent}
  • @@ -42,9 +39,9 @@ *

    * * @param - * The {@link Serializable} type returned by {@link #toSerializable(LogEvent)} + * The type returned by {@link #toSerializable(LogEvent)} */ -public interface Layout extends Encoder { +public interface Layout extends Encoder { /** * Main {@linkplain org.apache.logging.log4j.plugins.Configurable#elementType() plugin element type} for diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LifeCycle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LifeCycle.java index 87467c00c89..3087a7d7c70 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LifeCycle.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LifeCycle.java @@ -14,7 +14,6 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core; import java.util.concurrent.TimeUnit; @@ -64,9 +63,29 @@ enum State { void stop(); - boolean isStarted(); + default boolean isInitializing() { + return getState() == State.INITIALIZING; + } + + default boolean isInitialized() { + return getState() == State.INITIALIZED; + } + + default boolean isStarting() { + return getState() == State.STARTING; + } - boolean isStopped(); + default boolean isStarted() { + return getState() == State.STARTED; + } + + default boolean isStopping() { + return getState() == State.STOPPING; + } + + default boolean isStopped() { + return getState() == State.STOPPED; + } /** * Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java index b73e7874ccd..67c3b432660 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java @@ -14,32 +14,68 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core; -import java.io.Serializable; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.impl.LogEventBuilder; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.ReadOnlyStringMap; /** - * Provides contextual information about a logged message. A LogEvent must be {@link java.io.Serializable} so that it - * may be transmitted over a network connection. Besides containing a - * {@link org.apache.logging.log4j.message.Message}, a LogEvent has a corresponding - * {@link org.apache.logging.log4j.Level} that the message was logged at. If a - * {@link org.apache.logging.log4j.Marker} was used, then it is included here. The contents of the - * {@link org.apache.logging.log4j.ThreadContext} at the time of the log call are provided via - * {@link #getContextData()} and {@link #getContextStack()}. If a {@link java.lang.Throwable} was included in the log - * call, then it is provided via {@link #getThrown()}. When this class is serialized, the attached Throwable will - * be wrapped into a {@link org.apache.logging.log4j.core.impl.ThrowableProxy} so that it may be safely serialized - * and deserialized properly without causing problems if the exception class is not available on the other end. + * Provides the context in which a message was emitted by a logger. A LogEvent contains a + * {@linkplain #getMessage() message}, {@linkplain #getLevel() level}, optional {@linkplain #getMarker() marker}, + * optional {@linkplain #getThrown() exception}, and the contents of the {@link ThreadContext} + * {@linkplain #getContextData() map} and {@linkplain #getContextStack() stack}. + * + *

    Serializable Deprecation

    + *

    In Log4j 2.x, this interface implemented {@code Serializable}. In Log4j 3.x, this is no longer used. + * See LOG4J2-3228.

    */ -public interface LogEvent extends Serializable { +public interface LogEvent { + + /** + * Creates a new LogEventBuilder. + * + * @since 3.0.0 + */ + static LogEventBuilder builder() { + return new LogEventBuilder(); + } + + /** + * Creates a new LogEventBuilder using an existing LogEvent. + * + * @param other existing log event to copy data from + * @return new LogEventBuilder with copied data + * @since 3.0.0 + */ + static LogEventBuilder builderFrom(final LogEvent other) { + return new LogEventBuilder().copyFrom(other); + } + + /** + * Returns an immutable copy of this log event. + * + * @return copy of this + * @since 3.0.0 + */ + default LogEvent copy() { + return builderFrom(this).get(); + } + + /** + * Returns an immutable copy of this log event. + * + * @param includeLocation whether to calculate the caller location + * @return copy of this + * @since 3.0.0 + */ + default LogEvent copy(final boolean includeLocation) { + return builderFrom(this).includeLocation(includeLocation).get(); + } /** * Returns an immutable version of this log event, which MAY BE a copy of this event. @@ -139,7 +175,6 @@ public interface LogEvent extends Serializable { * Gets the thread name. * * @return thread name, may be null. - * TODO guess this could go into a thread context object too. (RG) Why? */ String getThreadName(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java index de55a524039..57c849713bc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.ReliabilityStrategy; import org.apache.logging.log4j.core.filter.CompositeFilter; +import org.apache.logging.log4j.message.FlowMessageFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.SimpleMessage; @@ -44,10 +45,6 @@ * Appenders} associated with this Logger. Note that access to these underlying objects is provided primarily for use in * unit tests or bridging legacy Log4j 1.x code. Future versions of this class may or may not include the various * methods that are noted as not being part of the public API. - * - * TODO All the isEnabled methods could be pushed into a filter interface. Not sure of the utility of having isEnabled - * be able to examine the message pattern and parameters. (RG) Moving the isEnabled methods out of Logger noticeably - * impacts performance. The message pattern and parameters are required so that they can be used in global filters. */ public class Logger extends AbstractLogger implements Supplier { @@ -58,7 +55,6 @@ public class Logger extends AbstractLogger implements Supplier { */ protected volatile PrivateConfig privateConfig; - // FIXME: ditto to the above private final LoggerContext context; /** @@ -69,7 +65,7 @@ public class Logger extends AbstractLogger implements Supplier { * @param name The name of the Logger. */ protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) { - super(name, messageFactory); + super(name, messageFactory, context.getFlowMessageFactory()); this.context = context; privateConfig = new PrivateConfig(context.getConfiguration(), this); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java index ae6e8312f05..21b7ec7ef76 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java @@ -18,24 +18,25 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.File; import java.lang.ref.WeakReference; import java.net.URI; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationListener; +import org.apache.logging.log4j.core.config.ConfigurationProvider; import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.NullConfiguration; @@ -46,17 +47,24 @@ import org.apache.logging.log4j.core.util.ExecutorServices; import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; +import org.apache.logging.log4j.message.FlowMessageFactory; import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.di.DI; import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.plugins.di.Key; +import org.apache.logging.log4j.plugins.di.SimpleScope; import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.spi.LoggerContextFactory; import org.apache.logging.log4j.spi.LoggerContextShutdownAware; import org.apache.logging.log4j.spi.LoggerContextShutdownEnabled; import org.apache.logging.log4j.spi.LoggerRegistry; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.Terminable; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.Cast; +import org.apache.logging.log4j.util.ContextPropertyResolver; +import org.apache.logging.log4j.util.PropertyResolver; import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER; @@ -69,125 +77,203 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.logging.log4j.spi.LoggerContext, AutoCloseable, Terminable, ConfigurationListener, LoggerContextShutdownEnabled { + public static Builder newBuilder() { + return new Builder(); + } + + public static class GenericBuilder> { + private String name; + private String key; + private Object externalContext; + private URI configLocation; + private Injector injector; + private PropertyResolver propertyResolver; + private MessageFactory messageFactory; + private FlowMessageFactory flowMessageFactory; + + public B asBuilder() { + return Cast.cast(this); + } + + public String getName() { + return name; + } + + public B setName(final String name) { + this.name = Objects.requireNonNull(name); + return asBuilder(); + } + + public String getKey() { + return key; + } + + public B setKey(final String key) { + this.key = key; + return asBuilder(); + } + + public Object getExternalContext() { + return externalContext; + } + + public B setExternalContext(final Object externalContext) { + this.externalContext = Objects.requireNonNull(externalContext); + return asBuilder(); + } + + public URI getConfigLocation() { + return configLocation; + } + + public B setConfigLocation(final String configLocation) { + if (configLocation != null) { + this.configLocation = NetUtils.toURI(configLocation); + } + return asBuilder(); + } + + public B setConfigLocation(final URI configLocation) { + if (configLocation != null) { + this.configLocation = configLocation; + } + return asBuilder(); + } + + /** + * Gets the Injector to use in the built LoggerContext. If no injector is specified, then a new injector is + * created and then {@linkplain Injector#init() initialized}. + * + * @return the initialized injector + */ + public Injector getInjector() { + if (injector == null) { + injector = DI.createInjector(); + injector.registerScope(ContextScoped.class, new SimpleScope(() -> "LoggerContext; name=" + getName())); + injector.init(); + } + return injector; + } + + /** + * Sets the Injector to use in the built LoggerContext. + * @param injector the initialized injector to use + * @return this + */ + @Inject + public B setInjector(final Injector injector) { + this.injector = injector; + return asBuilder(); + } + + /** + * Gets the PropertyResolver to use in the built LoggerContext. If no property resolver is specified, + * then a {@link ContextPropertyResolver} is created from the + * {@linkplain LoggingSystem#getPropertyResolver() default resolver} and {@linkplain #getName() this name}. + */ + public PropertyResolver getPropertyResolver() { + if (propertyResolver == null) { + propertyResolver = new ContextPropertyResolver(LoggingSystem.getPropertyResolver(), getName()); + } + return propertyResolver; + } + + /** + * Sets the PropertyResolver to use in the built LoggerContext. If no property resolver is specified, + * a {@link ContextPropertyResolver} will be created using {@link #getName()} as the context name and + * the {@linkplain LoggingSystem#getPropertyResolver() default property resolver} as the delegate. + */ + @Inject + public B setPropertyResolver(final PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + return asBuilder(); + } + + public MessageFactory getMessageFactory() { + if (messageFactory == null) { + messageFactory = LoggingSystem.createMessageFactory(getName()); + } + return messageFactory; + } + + public B setMessageFactory(final MessageFactory messageFactory) { + this.messageFactory = messageFactory; + return asBuilder(); + } + + public FlowMessageFactory getFlowMessageFactory() { + if (flowMessageFactory == null) { + flowMessageFactory = LoggingSystem.createFlowMessageFactory(getName()); + } + return flowMessageFactory; + } + + public B setFlowMessageFactory(final FlowMessageFactory flowMessageFactory) { + this.flowMessageFactory = flowMessageFactory; + return asBuilder(); + } + } + + public static class Builder extends GenericBuilder implements Supplier { + @Override + public LoggerContext get() { + return new LoggerContext(getName(), getKey(), getExternalContext(), getConfigLocation(), getInjector(), + getPropertyResolver(), getMessageFactory(), getFlowMessageFactory()); + } + } + /** * Property name of the property change event fired if the configuration is changed. */ public static final String PROPERTY_CONFIG = "config"; - public static final Key> KEY = new Key<>() {}; - - private static final Configuration NULL_CONFIGURATION = new NullConfiguration(); + public static final Key KEY = new Key<>() {}; private final LoggerRegistry loggerRegistry = new LoggerRegistry<>(); private final CopyOnWriteArrayList propertyChangeListeners = new CopyOnWriteArrayList<>(); private volatile List listeners; private final Injector injector; + private final PropertyResolver propertyResolver; + private final MessageFactory messageFactory; + private final FlowMessageFactory flowMessageFactory; /** * The Configuration is volatile to guarantee that initialization of the Configuration has completed before the * reference is updated. */ - private volatile Configuration configuration = new DefaultConfiguration(); + private volatile Configuration configuration; + // cached instance of NullConfiguration for switching to during shutdown + private final Configuration nullConfiguration; private static final String EXTERNAL_CONTEXT_KEY = "__EXTERNAL_CONTEXT_KEY__"; private final ConcurrentMap externalMap = new ConcurrentHashMap<>(); private String contextName; + private String contextKey; private volatile URI configLocation; private Cancellable shutdownCallback; private final Lock configLock = new ReentrantLock(); - /** - * Constructor taking only a name. - * - * @param name The context name. - */ - public LoggerContext(final String name) { - this(name, null, (URI) null); - } - - /** - * Constructor taking a name and a reference to an external context. - * - * @param name The context name. - * @param externalContext The external context. - */ - public LoggerContext(final String name, final Object externalContext) { - this(name, externalContext, (URI) null); - } - - /** - * Constructor taking a name, external context and a configuration URI. - * - * @param name The context name. - * @param externalContext The external context. - * @param configLocn The location of the configuration as a URI. - */ - public LoggerContext(final String name, final Object externalContext, final URI configLocn) { - this(name, externalContext, configLocn, DI.createInjector()); - injector.init(); - injector.registerBindingIfAbsent(KEY, () -> new WeakReference<>(this)); - } - - /** - * Constructs a LoggerContext with a name, external context, configuration URI, and an Injector. - * - * @param name context name - * @param externalContext external context or null - * @param configLocn location of configuration as a URI - * @param injector initialized Injector instance - */ - public LoggerContext(final String name, final Object externalContext, final URI configLocn, final Injector injector) { - this.contextName = name; - if (externalContext != null) { - externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext); - } - this.configLocation = configLocn; - this.injector = injector.copy(); - injector.registerBindingIfAbsent(KEY, () -> new WeakReference<>(this)); - } - - /** - * Constructor taking a name external context and a configuration location String. The location must be resolvable - * to a File. - * - * @param name The configuration location. - * @param externalContext The external context. - * @param configLocn The configuration location. - */ - public LoggerContext(final String name, final Object externalContext, final String configLocn) { - this(name, externalContext, configLocn, DI.createInjector()); - injector.init(); - injector.registerBindingIfAbsent(KEY, () -> new WeakReference<>(this)); - } - - /** - * Constructs a LoggerContext with a name, external context, configuration location string, and an Injector. - * The location must be resolvable to a File. - * - * @param name context name - * @param externalContext external context or null - * @param configLocn configuration location - * @param injector initialized Injector instance - */ - public LoggerContext(final String name, final Object externalContext, final String configLocn, final Injector injector) { - this.contextName = name; + protected LoggerContext(final String contextName, final String contextKey, final Object externalContext, + final URI configLocation, final Injector injector, final PropertyResolver propertyResolver, + final MessageFactory messageFactory, final FlowMessageFactory flowMessageFactory) { + this.contextName = contextName; + this.contextKey = contextKey; if (externalContext != null) { externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext); } - if (configLocn != null) { - URI uri; - try { - uri = new File(configLocn).toURI(); - } catch (final Exception ex) { - uri = null; - } - configLocation = uri; - } else { - configLocation = null; - } - this.injector = injector.copy(); - this.injector.registerBindingIfAbsent(KEY, () -> new WeakReference<>(this)); + this.configLocation = configLocation; + this.injector = injector; + this.propertyResolver = propertyResolver; + this.messageFactory = messageFactory; + this.flowMessageFactory = flowMessageFactory; + var ref = new WeakReference<>(this); + injector.registerBinding(KEY, ref::get) + .registerBinding(Key.forClass(PropertyResolver.class), this::getPropertyResolver) + .registerBinding(Configuration.KEY, this::getConfiguration); + this.configuration = new DefaultConfiguration(this); + this.nullConfiguration = new NullConfiguration(this); } + @Override public void addShutdownListener(final LoggerContextShutdownAware listener) { if (listeners == null) { synchronized(this) { @@ -199,6 +285,7 @@ public void addShutdownListener(final LoggerContextShutdownAware listener) { listeners.add(listener); } + @Override public List getListeners() { return listeners; } @@ -274,7 +361,8 @@ public static LoggerContext getContext(final ClassLoader loader, final boolean c @Override public void start() { LOGGER.debug("Starting {}...", this); - if (PropertiesUtil.getProperties().getBooleanProperty(Log4jProperties.LOGGER_CONTEXT_STACKTRACE_ON_START, false)) { + final boolean stacktraceOnStart = propertyResolver.getBoolean(Log4jProperties.LOGGER_CONTEXT_STACKTRACE_ON_START); + if (stacktraceOnStart) { LOGGER.debug("Stack trace to locate invoker", new Exception("Not a real error, showing stack trace to locate invoker")); } @@ -402,7 +490,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) { shutdownCallback = null; } final Configuration prev = configuration; - configuration = NULL_CONFIGURATION; + configuration = nullConfiguration; updateLoggers(); prev.stop(timeout, timeUnit); externalMap.clear(); @@ -433,6 +521,15 @@ public String getName() { return contextName; } + /** + * Gets the key for this context to use when indexing logger contexts. + * @return the context key + * @since 3.0.0 + */ + public String getKey() { + return contextKey; + } + /** * Gets the root logger. * @@ -452,6 +549,10 @@ public void setName(final String name) { contextName = Objects.requireNonNull(name); } + public void setKey(final String key) { + contextKey = Objects.requireNonNull(key); + } + @Override public Object getObject(final String key) { return externalMap.get(key); @@ -552,6 +653,7 @@ public Logger getLogger(final String name, final MessageFactory messageFactory) * @return the LoggerRegistry. * @since 2.17.2 */ + @Override public LoggerRegistry getLoggerRegistry() { return loggerRegistry; } @@ -566,6 +668,28 @@ public Injector getInjector() { return injector; } + public PropertyResolver getPropertyResolver() { + return propertyResolver; + } + + public MessageFactory getMessageFactory() { + return messageFactory; + } + + public FlowMessageFactory getFlowMessageFactory() { + return flowMessageFactory; + } + + @Override + public T getInstance(final Class type) { + return injector.getInstance(type); + } + + @Override + public Optional tryGetInstance(final Class type) { + return injector.tryGetInstance(type); + } + /** * Determines if the specified Logger exists. * @@ -647,6 +771,7 @@ public Configuration setConfiguration(final Configuration config) { final ConcurrentMap map = config.getComponent(Configuration.CONTEXT_PROPERTIES); + // TODO(ms): adding the hostName variable should be optional try { // LOG4J2-719 network access may throw android.os.NetworkOnMainThreadException // LOG4J2-2808 don't block unless necessary map.computeIfAbsent("hostName", s -> NetUtils.getLocalHostname()); @@ -723,7 +848,7 @@ private void reconfigure(final URI configURI) { LOGGER.debug("Reconfiguration started for {} at URI {} with optional ClassLoader: {}", this, configURI, cl); final Configuration instance = - injector.getInstance(ConfigurationFactory.KEY).getConfiguration(this, contextName, configURI, cl); + getInstance(ConfigurationProvider.class).getConfiguration(contextName, configURI, cl); if (instance == null) { LOGGER.error("Reconfiguration failed: No configuration found for '{}' at '{}' in '{}'", contextName, configURI, cl); } else { @@ -787,7 +912,7 @@ public void updateLoggers(final Configuration config) { public synchronized void onChange(final Reconfigurable reconfigurable) { final long startMillis = System.currentTimeMillis(); LOGGER.debug("Reconfiguration started for context {} ({})", contextName, this); - initApiModule(); + ThreadContext.init(); final Configuration newConfig = reconfigurable.reconfigure(); if (newConfig != null) { setConfiguration(newConfig); @@ -804,10 +929,6 @@ public String toString() { return "LoggerContext[" + contextName + "]"; } - private void initApiModule() { - ThreadContext.init(); - } - // LOG4J2-151: changed visibility from private to protected protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) { return new Logger(ctx, name, messageFactory); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxy.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxy.java index 1e4d3d889d5..20a6a2b0442 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxy.java @@ -14,9 +14,8 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.impl; +package org.apache.logging.log4j.core; -import java.io.Serializable; import java.util.Arrays; import java.util.Deque; import java.util.HashMap; @@ -38,22 +37,13 @@ * deserializes a ThrowableProxy, the throwable may not be set, but the throwable's information is preserved in other * fields of the proxy like the message and stack trace. *

    - * - *

    - * TODO: Move this class to org.apache.logging.log4j.core because it is used from LogEvent. - *

    - *

    - * TODO: Deserialize: Try to rebuild Throwable if the target exception is in this class loader? - *

    */ -public class ThrowableProxy implements Serializable { +public class ThrowableProxy { private static final char EOL = '\n'; private static final String EOL_STR = String.valueOf(EOL); - private static final long serialVersionUID = -2752771578252251910L; - private final ThrowableProxy causeProxy; private int commonElementCount; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyHelper.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyHelper.java index 66b701447f4..849d7d3d8c1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyHelper.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyHelper.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.impl; +package org.apache.logging.log4j.core; import java.net.URL; import java.security.CodeSource; @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; +import org.apache.logging.log4j.core.impl.ExtendedClassInfo; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.LoaderUtil; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyRenderer.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyRenderer.java index f13943a5245..d5bb5d438d6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxyRenderer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ThrowableProxyRenderer.java @@ -14,13 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.impl; +package org.apache.logging.log4j.core; + +import java.util.List; import org.apache.logging.log4j.core.pattern.TextRenderer; import org.apache.logging.log4j.util.Strings; -import java.util.List; - /** * {@link ThrowableProxyRenderer} is an internal utility providing the code to render a {@link ThrowableProxy} * to a {@link StringBuilder}. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java index 98274243a9a..6943cc0868b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.Serializable; import java.nio.charset.Charset; import java.util.Objects; @@ -27,13 +26,13 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; -import org.apache.logging.log4j.plugins.PluginElement; -import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.core.filter.AbstractFilterable; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.Integers; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginElement; +import org.apache.logging.log4j.plugins.validation.constraints.Required; /** * Abstract base class for Appenders. Although Appenders do not have to extend this class, doing so will simplify their @@ -52,7 +51,7 @@ public abstract static class Builder> extends AbstractFilte private boolean ignoreExceptions = true; @PluginElement("Layout") - private Layout layout; + private Layout layout; @PluginBuilderAttribute @Required(message = "No appender name provided") @@ -69,7 +68,7 @@ public boolean isIgnoreExceptions() { return ignoreExceptions; } - public Layout getLayout() { + public Layout getLayout() { return layout; } @@ -83,21 +82,24 @@ public B setIgnoreExceptions(final boolean ignoreExceptions) { return asBuilder(); } - public B setLayout(final Layout layout) { + public B setLayout(final Layout layout) { this.layout = layout; return asBuilder(); } - public Layout getOrCreateLayout() { + public Layout getOrCreateLayout() { if (layout == null) { - return PatternLayout.createDefaultLayout(); + return PatternLayout.createDefaultLayout(configuration); } return layout; } - public Layout getOrCreateLayout(final Charset charset) { + public Layout getOrCreateLayout(final Charset charset) { if (layout == null) { - return PatternLayout.newBuilder().setCharset(charset).build(); + layout = PatternLayout.newBuilder() + .setConfiguration(configuration) + .setCharset(charset) + .build(); } return layout; } @@ -115,7 +117,7 @@ public Configuration getConfiguration() { private final String name; private final boolean ignoreExceptions; - private final Layout layout; + private final Layout layout; private ErrorHandler handler = new DefaultErrorHandler(this); /** @@ -128,7 +130,7 @@ public Configuration getConfiguration() { * then passed to the application. * @param properties Optional properties */ - protected AbstractAppender(final String name, final Filter filter, final Layout layout, + protected AbstractAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, final Property[] properties) { super(filter, properties); this.name = Objects.requireNonNull(name, "name"); @@ -145,7 +147,7 @@ protected AbstractAppender(final String name, final Filter filter, final Layout< * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])}. */ @Deprecated - protected AbstractAppender(final String name, final Filter filter, final Layout layout) { + protected AbstractAppender(final String name, final Filter filter, final Layout layout) { this(name, filter, layout, true, Property.EMPTY_ARRAY); } @@ -160,7 +162,7 @@ protected AbstractAppender(final String name, final Filter filter, final Layout< * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])} */ @Deprecated - protected AbstractAppender(final String name, final Filter filter, final Layout layout, + protected AbstractAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions) { this(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY); } @@ -226,7 +228,7 @@ public ErrorHandler getHandler() { * @return The Layout used to format the event. */ @Override - public Layout getLayout() { + public Layout getLayout() { return layout; } @@ -276,7 +278,7 @@ public void setHandler(final ErrorHandler handler) { * the event to serialize. * @return the serialized event or null if no layout is present. */ - protected Serializable toSerializable(final LogEvent event) { + protected Object toSerializable(final LogEvent event) { return layout != null ? layout.toSerializable(event) : null; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java index 83ca21ee99d..654074d5933 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractFileAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.Serializable; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -24,9 +23,9 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import org.apache.logging.log4j.core.net.Advertiser; /** * Abstract File Appender. @@ -158,7 +157,7 @@ public B setFileGroup(final String fileGroup) { private final Object advertisement; - private AbstractFileAppender(final String name, final Layout layout, final Filter filter, + private AbstractFileAppender(final String name, final Layout layout, final Filter filter, final M manager, final String filename, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser, final Property[] properties) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java index b74c8b14f03..5affabcb0da 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java @@ -29,6 +29,7 @@ import org.apache.logging.log4j.core.config.ConfigurationException; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Cast; /** * Abstract base class used to register managers. @@ -107,8 +108,7 @@ public static M getManager(final String name, fin final T data) { LOCK.lock(); try { - @SuppressWarnings("unchecked") - M manager = (M) MAP.get(name); + M manager = Cast.cast(MAP.get(name)); if (manager == null) { manager = factory.createManager(name, data); if (manager == null) { @@ -162,7 +162,7 @@ public static boolean hasManager(final String name) { */ protected static M narrow(final Class narrowClass, final AbstractManager manager) { if (narrowClass.isAssignableFrom(manager.getClass())) { - return (M) manager; + return narrowClass.cast(manager); } throw new ConfigurationException( "Configuration has multiple incompatible Appenders pointing to the same resource '" + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java index 9189af9231e..952be7b4e66 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java @@ -16,15 +16,14 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.Serializable; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; -import org.apache.logging.log4j.core.util.Constants; /** * Appends log events as bytes to a byte output stream. The stream encoding is defined in the layout. @@ -44,7 +43,7 @@ public abstract static class Builder> extends AbstractAppen private boolean bufferedIo = true; @PluginBuilderAttribute - private int bufferSize = Constants.ENCODER_BYTE_BUFFER_SIZE; + private int bufferSize = GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize(); @PluginBuilderAttribute private boolean immediateFlush = true; @@ -97,7 +96,7 @@ public B setBufferSize(final int bufferSize) { * @param properties Optional properties. * @param manager The OutputStreamManager. */ - protected AbstractOutputStreamAppender(final String name, final Layout layout, + protected AbstractOutputStreamAppender(final String name, final Layout layout, final Filter filter, final boolean ignoreExceptions, final boolean immediateFlush, final Property[] properties, final M manager) { super(name, filter, layout, ignoreExceptions, properties); @@ -169,7 +168,7 @@ public void append(final LogEvent event) { } private void tryAppend(final LogEvent event) { - if (Constants.ENABLE_DIRECT_ENCODERS) { + if (GarbageFreeConfiguration.getDefaultConfiguration().isDirectEncodersEnabled()) { directEncodeEvent(event); } else { writeByteArrayToManager(event); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java index 6a3c9c9d0a8..98e2613f769 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java @@ -16,6 +16,14 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TransferQueue; +import java.util.function.Supplier; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; @@ -32,24 +40,18 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationException; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.filter.AbstractFilterable; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Factory; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginAliases; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.spi.AbstractLogger; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TransferQueue; +import org.apache.logging.log4j.util.InternalApi; /** * Appends to one or more Appenders asynchronously. You can configure an AsyncAppender with one or more Appenders and an @@ -73,12 +75,15 @@ public final class AsyncAppender extends AbstractAppender { private AppenderControl errorAppender; private AsyncAppenderEventDispatcher dispatcher; private AsyncQueueFullPolicy asyncQueueFullPolicy; + private final Supplier asyncQueueFullPolicySupplier; private AsyncAppender(final String name, final Filter filter, final AppenderRef[] appenderRefs, - final String errorRef, final int queueSize, final boolean blocking, final boolean ignoreExceptions, - final long shutdownTimeout, final Configuration config, final boolean includeLocation, - final BlockingQueueFactory blockingQueueFactory, final Property[] properties) { + final String errorRef, final int queueSize, final boolean blocking, final boolean ignoreExceptions, + final long shutdownTimeout, final Configuration config, final boolean includeLocation, + final BlockingQueueFactory blockingQueueFactory, final Property[] properties, + final Supplier asyncQueueFullPolicySupplier) { super(name, filter, null, ignoreExceptions, properties); + this.asyncQueueFullPolicySupplier = asyncQueueFullPolicySupplier; this.queue = blockingQueueFactory.create(queueSize); this.queueSize = queueSize; this.blocking = blocking; @@ -115,7 +120,7 @@ public void start() { } else if (errorRef == null) { throw new ConfigurationException("No appenders are available for AsyncAppender " + getName()); } - asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create(); + asyncQueueFullPolicy = asyncQueueFullPolicySupplier.get(); dispatcher.start(); super.start(); @@ -153,7 +158,7 @@ public void append(final LogEvent logEvent) { if (!isStarted()) { throw new IllegalStateException("AsyncAppender " + getName() + " is not active"); } - final Log4jLogEvent memento = Log4jLogEvent.createMemento(logEvent, includeLocation); + final LogEvent memento = logEvent.copy(includeLocation); InternalAsyncUtil.makeMessageImmutable(logEvent.getMessage()); if (!transfer(memento)) { if (blocking) { @@ -184,6 +189,7 @@ private boolean transfer(final LogEvent memento) { * * @param logEvent the event to log */ + @InternalApi public void logMessageInCurrentThread(final LogEvent logEvent) { logEvent.setEndOfBatch(queue.isEmpty()); dispatcher.dispatch(logEvent); @@ -194,6 +200,7 @@ public void logMessageInCurrentThread(final LogEvent logEvent) { * * @param logEvent the event to log */ + @InternalApi public void logMessageInBackgroundThread(final LogEvent logEvent) { try { // wait for free slots in the queue @@ -232,7 +239,7 @@ private void logToErrorAppenderIfNecessary(final boolean appendSuccessful, final } } - @PluginBuilderFactory + @Factory public static Builder newBuilder() { return new Builder(); } @@ -273,60 +280,72 @@ public static class Builder> extends AbstractFilterable.Bui @PluginElement(BlockingQueueFactory.ELEMENT_TYPE) private BlockingQueueFactory blockingQueueFactory = new ArrayBlockingQueueFactory<>(); - public Builder setAppenderRefs(final AppenderRef[] appenderRefs) { + private Supplier asyncQueueFullPolicySupplier; + + public B setAppenderRefs(final AppenderRef[] appenderRefs) { this.appenderRefs = appenderRefs; - return this; + return asBuilder(); } - public Builder setErrorRef(final String errorRef) { + public B setErrorRef(final String errorRef) { this.errorRef = errorRef; - return this; + return asBuilder(); } - public Builder setBlocking(final boolean blocking) { + public B setBlocking(final boolean blocking) { this.blocking = blocking; - return this; + return asBuilder(); } - public Builder setShutdownTimeout(final long shutdownTimeout) { + public B setShutdownTimeout(final long shutdownTimeout) { this.shutdownTimeout = shutdownTimeout; - return this; + return asBuilder(); } - public Builder setBufferSize(final int bufferSize) { + public B setBufferSize(final int bufferSize) { this.bufferSize = bufferSize; - return this; + return asBuilder(); } - public Builder setName(final String name) { + public B setName(final String name) { this.name = name; - return this; + return asBuilder(); } - public Builder setIncludeLocation(final boolean includeLocation) { + public B setIncludeLocation(final boolean includeLocation) { this.includeLocation = includeLocation; - return this; + return asBuilder(); } - public Builder setConfiguration(final Configuration configuration) { + public B setConfiguration(final Configuration configuration) { this.configuration = configuration; - return this; + return asBuilder(); } - public Builder setIgnoreExceptions(final boolean ignoreExceptions) { + public B setIgnoreExceptions(final boolean ignoreExceptions) { this.ignoreExceptions = ignoreExceptions; - return this; + return asBuilder(); } - public Builder setBlockingQueueFactory(final BlockingQueueFactory blockingQueueFactory) { + public B setBlockingQueueFactory(final BlockingQueueFactory blockingQueueFactory) { this.blockingQueueFactory = blockingQueueFactory; - return this; + return asBuilder(); + } + + @Inject + public B setAsyncQueueFullPolicySupplier(final Supplier asyncQueueFullPolicySupplier) { + this.asyncQueueFullPolicySupplier = asyncQueueFullPolicySupplier; + return asBuilder(); } @Override public AsyncAppender build() { + if (asyncQueueFullPolicySupplier == null) { + asyncQueueFullPolicySupplier = configuration.getInstance(AsyncQueueFullPolicyFactory.class); + } return new AsyncAppender(name, getFilter(), appenderRefs, errorRef, bufferSize, blocking, ignoreExceptions, - shutdownTimeout, configuration, includeLocation, blockingQueueFactory, getPropertyArray()); + shutdownTimeout, configuration, includeLocation, blockingQueueFactory, getPropertyArray(), + asyncQueueFullPolicySupplier); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppenderEventDispatcher.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppenderEventDispatcher.java index b2d0b66eaf9..00a2c6c4d73 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppenderEventDispatcher.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppenderEventDispatcher.java @@ -16,21 +16,20 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.AppenderControl; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.Log4jThread; import org.apache.logging.log4j.status.StatusLogger; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - class AsyncAppenderEventDispatcher extends Log4jThread { - private static final LogEvent STOP_EVENT = new Log4jLogEvent(); + private static final LogEvent STOP_EVENT = LogEvent.builder().toImmutable(); private static final AtomicLong THREAD_COUNTER = new AtomicLong(0); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java index 64b6ef487ee..02ad360c130 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; -import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import java.nio.charset.Charset; @@ -40,9 +39,11 @@ import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.util.Chars; +import org.apache.logging.log4j.util.Constants; import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; /** * Appends log events to System.out or System.err using a layout specified by the user. The @@ -97,13 +98,13 @@ protected Charset getCharset(final String property, final Charset defaultCharset } - private ConsoleAppender(final String name, final Layout layout, final Filter filter, + private ConsoleAppender(final String name, final Layout layout, final Filter filter, final OutputStreamManager manager, final boolean ignoreExceptions, final Target target, final Property[] properties) { super(name, layout, filter, ignoreExceptions, true, properties, manager); this.target = target; } - public static ConsoleAppender createDefaultAppenderForLayout(final Layout layout) { + public static ConsoleAppender createDefaultAppenderForLayout(final Layout layout) { // this method cannot use the builder class without introducing an infinite loop due to DefaultConfiguration return new ConsoleAppender("DefaultConsole-" + COUNT.incrementAndGet(), layout, null, getDefaultManager(DEFAULT_TARGET, false, false, layout), true, DEFAULT_TARGET, null); @@ -151,14 +152,14 @@ public ConsoleAppender build() { if (follow && direct) { throw new IllegalArgumentException("Cannot use both follow and direct on ConsoleAppender '" + getName() + "'"); } - final Layout layout = getOrCreateLayout(target.getDefaultCharset()); + final Layout layout = getOrCreateLayout(target.getDefaultCharset()); return new ConsoleAppender(getName(), layout, getFilter(), getManager(target, follow, direct, layout), isIgnoreExceptions(), target, getPropertyArray()); } } private static OutputStreamManager getDefaultManager(final Target target, final boolean follow, final boolean direct, - final Layout layout) { + final Layout layout) { final OutputStream os = getOutputStream(follow, direct, target); // LOG4J2-1176 DefaultConfiguration should not share OutputStreamManager instances to avoid memory leaks. @@ -167,7 +168,7 @@ private static OutputStreamManager getDefaultManager(final Target target, final } private static OutputStreamManager getManager(final Target target, final boolean follow, final boolean direct, - final Layout layout) { + final Layout layout) { final OutputStream os = getOutputStream(follow, direct, target); final String managerName = target.name() + '.' + follow + '.' + direct; return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory); @@ -188,8 +189,8 @@ private static OutputStream getOutputStream(final boolean follow, final boolean } catch (final UnsupportedEncodingException ex) { // should never happen throw new IllegalStateException("Unsupported default encoding " + enc, ex); } - final PropertyEnvironment properties = PropertiesUtil.getProperties(); - if (!properties.isOsWindows() || properties.getBooleanProperty(Log4jProperties.JANSI_DISABLED, true) || direct) { + final PropertyResolver resolver = LoggingSystem.getPropertyResolver(); + if (!Constants.isWindows() || !resolver.getBoolean(Log4jProperties.JANSI_ENABLED) || direct) { return outputStream; } try { @@ -283,7 +284,7 @@ public void write(final int b) throws IOException { private static class FactoryData { private final OutputStream os; private final String name; - private final Layout layout; + private final Layout layout; /** * Constructor. @@ -292,7 +293,7 @@ private static class FactoryData { * @param type The name of the target. * @param layout A Serializable layout */ - public FactoryData(final OutputStream os, final String type, final Layout layout) { + public FactoryData(final OutputStream os, final String type, final Layout layout) { this.os = os; this.name = type; this.layout = layout; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java index 40fde52bbb8..7233ccebd28 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; @@ -32,11 +37,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - /** * The FailoverAppender will capture exceptions in an Appender and then route the event * to a different appender. Hopefully it is obvious that the Appenders must be configured @@ -193,10 +193,10 @@ public static FailoverAppender createAppender( final int retryIntervalMillis; if (retryIntervalSeconds >= 0) { - retryIntervalMillis = retryIntervalSeconds * Constants.MILLIS_IN_SECONDS; + retryIntervalMillis = Math.toIntExact(TimeUnit.SECONDS.toMillis(retryIntervalSeconds)); } else { LOGGER.warn("Interval {} is less than zero. Using default", retryIntervalSeconds); - retryIntervalMillis = DEFAULT_INTERVAL_SECONDS * Constants.MILLIS_IN_SECONDS; + retryIntervalMillis = Math.toIntExact(TimeUnit.SECONDS.toMillis(DEFAULT_INTERVAL_SECONDS)); } return new FailoverAppender(name, filter, primary, failovers, retryIntervalMillis, config, ignoreExceptions, Property.EMPTY_ARRAY); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java index cd22aa3e0cb..b1bbd3f9873 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -27,11 +31,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - /** * File Appender. */ @@ -89,7 +88,7 @@ public FileAppender build() { if (!bufferedIo && bufferSize > 0) { LOGGER.warn("The bufferSize is set to {} but bufferedIo is false: {}", bufferSize, bufferedIo); } - final Layout layout = getOrCreateLayout(); + final Layout layout = getOrCreateLayout(); final FileManager manager = FileManager.getFileManager(fileName, append, locking, bufferedIo, createOnDemand, advertiseUri, layout, bufferSize, filePermissions, fileOwner, fileGroup, getConfiguration()); @@ -195,7 +194,7 @@ public static > B newBuilder() { private final Object advertisement; - private FileAppender(final String name, final Layout layout, final Filter filter, + private FileAppender(final String name, final Layout layout, final Filter filter, final FileManager manager, final String filename, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser, final Property[] properties) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java index 0a673e53601..82eea95b43e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java @@ -20,7 +20,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; @@ -41,8 +40,10 @@ import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; +import org.apache.logging.log4j.spi.LoggingSystem; +import org.apache.logging.log4j.util.PropertyResolver; /** @@ -66,7 +67,7 @@ public class FileManager extends OutputStreamManager { * @since 2.9 */ protected FileManager(final LoggerContext loggerContext, final String fileName, final OutputStream os, final boolean append, final boolean locking, - final boolean createOnDemand, final String advertiseURI, final Layout layout, + final boolean createOnDemand, final String advertiseURI, final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final boolean writeHeader, final ByteBuffer buffer) { super(loggerContext, os, fileName, createOnDemand, layout, writeHeader, buffer); @@ -122,7 +123,7 @@ protected FileManager(final LoggerContext loggerContext, final String fileName, */ public static FileManager getFileManager(final String fileName, final boolean append, boolean locking, final boolean bufferedIo, final boolean createOnDemand, final String advertiseUri, - final Layout layout, + final Layout layout, final int bufferSize, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { @@ -329,7 +330,7 @@ private static class FactoryData extends ConfigurationFactoryData { private final int bufferSize; private final boolean createOnDemand; private final String advertiseURI; - private final Layout layout; + private final Layout layout; private final String filePermissions; private final String fileOwner; private final String fileGroup; @@ -349,7 +350,7 @@ private static class FactoryData extends ConfigurationFactoryData { * @param configuration the configuration */ public FactoryData(final boolean append, final boolean locking, final boolean bufferedIo, final int bufferSize, - final boolean createOnDemand, final String advertiseURI, final Layout layout, + final boolean createOnDemand, final String advertiseURI, final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { super(configuration); @@ -382,11 +383,14 @@ public FileManager createManager(final String name, final FactoryData data) { final File file = new File(name); try { FileUtils.makeParentDirs(file); - final int actualSize = data.bufferedIo ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE; + final LoggerContext loggerContext = data.getLoggerContext(); + final PropertyResolver resolver = loggerContext != null ? loggerContext.getPropertyResolver() : LoggingSystem.getPropertyResolver(); + final GarbageFreeConfiguration configuration = new GarbageFreeConfiguration(resolver); + final int actualSize = data.bufferedIo ? data.bufferSize : configuration.getEncoderByteBufferSize(); final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[actualSize]); final FileOutputStream fos = data.createOnDemand ? null : new FileOutputStream(file, data.append); final boolean writeHeader = file.exists() && file.length() == 0; - final FileManager fm = new FileManager(data.getLoggerContext(), name, fos, data.append, data.locking, + final FileManager fm = new FileManager(loggerContext, name, fos, data.append, data.locking, data.createOnDemand, data.advertiseURI, data.layout, data.filePermissions, data.fileOwner, data.fileGroup, writeHeader, byteBuffer); if (fos != null && fm.attributeViewEnabled) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java index 2a188743455..d27fb0bee67 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java @@ -14,9 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender; +import java.net.URL; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -30,11 +33,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.net.URL; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - /** * Sends log events over HTTP. @@ -153,7 +151,7 @@ public static > B newBuilder() { private final HttpManager manager; - private HttpAppender(final String name, final Layout layout, final Filter filter, + private HttpAppender(final String name, final Layout layout, final Filter filter, final boolean ignoreExceptions, final HttpManager manager, final Property[] properties) { super(name, filter, layout, ignoreExceptions, properties); Objects.requireNonNull(layout, "layout"); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java index 91b08532083..0be50bc2d84 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -27,11 +31,6 @@ import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginFactory; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - /** * Memory Mapped File Appender. * @@ -79,7 +78,7 @@ public MemoryMappedFileAppender build() { LOGGER.error("No filename provided for MemoryMappedFileAppender with name " + name); return null; } - final Layout layout = getOrCreateLayout(); + final Layout layout = getOrCreateLayout(); final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(fileName, append, isImmediateFlush(), actualRegionLength, advertiseURI, layout); if (manager == null) { @@ -125,7 +124,7 @@ public B setAdvertiseURI(final String advertiseURI) { private Object advertisement; private final Advertiser advertiser; - private MemoryMappedFileAppender(final String name, final Layout layout, + private MemoryMappedFileAppender(final String name, final Layout layout, final Filter filter, final MemoryMappedFileManager manager, final String filename, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser, final Property[] properties) { super(name, layout, filter, ignoreExceptions, immediateFlush, properties, manager); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileManager.java index 587ffed469c..c4e808b0b7c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileManager.java @@ -16,17 +16,10 @@ */ package org.apache.logging.log4j.core.appender; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.util.Closer; -import org.apache.logging.log4j.core.util.FileUtils; -import org.apache.logging.log4j.core.util.NullOutputStream; -import org.apache.logging.log4j.util.ReflectionUtil; - import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; -import java.io.Serializable; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -39,6 +32,11 @@ import java.util.Map; import java.util.Objects; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.util.ReflectionUtil; + //Lines too long... //CHECKSTYLE:OFF /** @@ -75,7 +73,7 @@ public class MemoryMappedFileManager extends OutputStreamManager { protected MemoryMappedFileManager(final RandomAccessFile file, final String fileName, final OutputStream os, final boolean immediateFlush, final long position, final int regionLength, final String advertiseURI, - final Layout layout, final boolean writeHeader) throws IOException { + final Layout layout, final boolean writeHeader) throws IOException { super(os, fileName, layout, writeHeader, ByteBuffer.wrap(new byte[0])); this.immediateFlush = immediateFlush; this.randomAccessFile = Objects.requireNonNull(file, "RandomAccessFile"); @@ -99,7 +97,7 @@ protected MemoryMappedFileManager(final RandomAccessFile file, final String file */ public static MemoryMappedFileManager getFileManager(final String fileName, final boolean append, final boolean immediateFlush, final int regionLength, final String advertiseURI, - final Layout layout) { + final Layout layout) { return narrow(MemoryMappedFileManager.class, getManager(fileName, new FactoryData(append, immediateFlush, regionLength, advertiseURI, layout), FACTORY)); } @@ -301,7 +299,7 @@ private static class FactoryData { private final boolean immediateFlush; private final int regionLength; private final String advertiseURI; - private final Layout layout; + private final Layout layout; /** * Constructor. @@ -313,7 +311,7 @@ private static class FactoryData { * @param layout The layout. */ public FactoryData(final boolean append, final boolean immediateFlush, final int regionLength, - final String advertiseURI, final Layout layout) { + final String advertiseURI, final Layout layout) { this.append = append; this.immediateFlush = immediateFlush; this.regionLength = regionLength; @@ -344,7 +342,7 @@ public MemoryMappedFileManager createManager(final String name, final FactoryDat } final boolean writeHeader = !data.append || !file.exists(); - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); RandomAccessFile raf = null; try { FileUtils.makeParentDirs(file); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java index 86b36f77994..9ae8c520870 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java @@ -1,173 +1,136 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.appender; - -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.util.CloseShieldOutputStream; -import org.apache.logging.log4j.core.util.NullOutputStream; -import org.apache.logging.log4j.plugins.Configurable; -import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginFactory; - -import java.io.OutputStream; -import java.io.Serializable; - -/** - * Appends log events to a given output stream using a layout. - *

    - * Character encoding is handled within the Layout. - *

    - */ -@Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) -@Plugin("OutputStream") -public final class OutputStreamAppender extends AbstractOutputStreamAppender { - - /** - * Builds OutputStreamAppender instances. - * - * @param - * The type to build. - */ - public static class Builder> extends AbstractOutputStreamAppender.Builder - implements org.apache.logging.log4j.plugins.util.Builder { - - private boolean follow = false; - - private final Layout layout = PatternLayout.createDefaultLayout(); - - private OutputStream target; - - @Override - public OutputStreamAppender build() { - - return new OutputStreamAppender(getName(), layout, getFilter(), getManager(target, follow, layout), isIgnoreExceptions(), getPropertyArray()); - } - - public B setFollow(final boolean shouldFollow) { - this.follow = shouldFollow; - return asBuilder(); - } - - public B setTarget(final OutputStream aTarget) { - this.target = aTarget; - return asBuilder(); - } - } - /** - * Holds data to pass to factory method. - */ - private static class FactoryData { - private final Layout layout; - private final String name; - private final OutputStream os; - - /** - * Builds instances. - * - * @param os - * The OutputStream. - * @param type - * The name of the target. - * @param layout - * A Serializable layout - */ - public FactoryData(final OutputStream os, final String type, final Layout layout) { - this.os = os; - this.name = type; - this.layout = layout; - } - } - - /** - * Creates the manager. - */ - private static class OutputStreamManagerFactory implements ManagerFactory { - - /** - * Creates an OutputStreamManager. - * - * @param name - * The name of the entity to manage. - * @param data - * The data required to create the entity. - * @return The OutputStreamManager - */ - @Override - public OutputStreamManager createManager(final String name, final FactoryData data) { - return new OutputStreamManager(data.os, data.name, data.layout, true); - } - } - - private static final OutputStreamManagerFactory factory = new OutputStreamManagerFactory(); - - /** - * Creates an OutputStream Appender. - * - * @param layout - * The layout to use or null to get the default layout. - * @param filter - * The Filter or null. - * @param target - * an output stream. - * @param follow - * If true will follow changes to the underlying output stream. - * Use false as the default. - * @param name - * The name of the Appender (required). - * @param ignore - * If {@code "true"} (default) exceptions encountered when - * appending events are logged; otherwise they are propagated to - * the caller. Use true as the default. - * @return The ConsoleAppender. - */ - @PluginFactory - public static OutputStreamAppender createAppender(Layout layout, final Filter filter, - final OutputStream target, final String name, final boolean follow, final boolean ignore) { - if (name == null) { - LOGGER.error("No name provided for OutputStreamAppender"); - return null; - } - if (layout == null) { - layout = PatternLayout.createDefaultLayout(); - } - return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null); - } - - private static OutputStreamManager getManager(final OutputStream target, final boolean follow, - final Layout layout) { - final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target); - final OutputStream targetRef = target == null ? os : target; - final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode()) - + '.' + follow; - return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory); - } - - @PluginFactory - public static > B newBuilder() { - return new Builder().asBuilder(); - } - - private OutputStreamAppender(final String name, final Layout layout, final Filter filter, - final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) { - super(name, layout, filter, ignoreExceptions, true, null, manager); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender; + +import java.io.OutputStream; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.util.CloseShieldOutputStream; +import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginFactory; + +/** + * Appends log events to a given output stream using a layout. + *

    + * Character encoding is handled within the Layout. + *

    + */ +@Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) +@Plugin("OutputStream") +public final class OutputStreamAppender extends AbstractOutputStreamAppender { + + /** + * Builds OutputStreamAppender instances. + * + * @param + * The type to build. + */ + public static class Builder> extends AbstractOutputStreamAppender.Builder + implements org.apache.logging.log4j.plugins.util.Builder { + + private boolean follow = false; + + private OutputStream target; + + @Override + public OutputStreamAppender build() { + final Layout layout = getOrCreateLayout(); + return new OutputStreamAppender(getName(), layout, getFilter(), getManager(target, follow, layout), isIgnoreExceptions(), getPropertyArray()); + } + + public B setFollow(final boolean shouldFollow) { + this.follow = shouldFollow; + return asBuilder(); + } + + public B setTarget(final OutputStream aTarget) { + this.target = aTarget; + return asBuilder(); + } + } + /** + * Holds data to pass to factory method. + */ + private static class FactoryData { + private final Layout layout; + private final String name; + private final OutputStream os; + + /** + * Builds instances. + * + * @param os + * The OutputStream. + * @param type + * The name of the target. + * @param layout + * A Serializable layout + */ + public FactoryData(final OutputStream os, final String type, final Layout layout) { + this.os = os; + this.name = type; + this.layout = layout; + } + } + + /** + * Creates the manager. + */ + private static class OutputStreamManagerFactory implements ManagerFactory { + + /** + * Creates an OutputStreamManager. + * + * @param name + * The name of the entity to manage. + * @param data + * The data required to create the entity. + * @return The OutputStreamManager + */ + @Override + public OutputStreamManager createManager(final String name, final FactoryData data) { + return new OutputStreamManager(data.os, data.name, data.layout, true); + } + } + + private static final OutputStreamManagerFactory factory = new OutputStreamManagerFactory(); + + private static OutputStreamManager getManager(final OutputStream target, final boolean follow, + final Layout layout) { + final OutputStream os = target == null ? OutputStream.nullOutputStream() : new CloseShieldOutputStream(target); + final OutputStream targetRef = target == null ? os : target; + final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode()) + + '.' + follow; + return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory); + } + + @PluginFactory + public static > B newBuilder() { + return new Builder().asBuilder(); + } + + private OutputStreamAppender(final String name, final Layout layout, final Filter filter, + final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) { + super(name, layout, filter, ignoreExceptions, true, null, manager); + } + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java index 34fdc1579c9..f55d22bcc72 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.nio.Buffer; import java.nio.ByteBuffer; import java.util.Objects; @@ -28,7 +27,7 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.layout.ByteBufferDestination; import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; /** * Manages an OutputStream so that it can be shared by multiple Appenders and will @@ -42,7 +41,7 @@ public class OutputStreamManager extends AbstractManager implements ByteBufferDe protected OutputStreamManager(final OutputStream os, final String streamName, final Layout layout, final boolean writeHeader) { - this(os, streamName, layout, writeHeader, Constants.ENCODER_BYTE_BUFFER_SIZE); + this(os, streamName, layout, writeHeader, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } protected OutputStreamManager(final OutputStream os, final String streamName, final Layout layout, @@ -70,7 +69,7 @@ protected OutputStreamManager(final OutputStream os, final String streamName, fi * @since 2.7 */ protected OutputStreamManager(final LoggerContext loggerContext, final OutputStream os, final String streamName, - final boolean createOnDemand, final Layout layout, final boolean writeHeader, + final boolean createOnDemand, final Layout layout, final boolean writeHeader, final ByteBuffer byteBuffer) { super(loggerContext, streamName); if (createOnDemand && os != null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java index 2cac501a6ad..5f3bf72deb9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -25,11 +29,6 @@ import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginFactory; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - /** * File Appender. */ @@ -74,7 +73,7 @@ public RandomAccessFileAppender build() { LOGGER.error("No filename provided for RandomAccessFileAppender with name {}", name); return null; } - final Layout layout = getOrCreateLayout(); + final Layout layout = getOrCreateLayout(); final boolean immediateFlush = isImmediateFlush(); final RandomAccessFileManager manager = RandomAccessFileManager.getFileManager(fileName, append, immediateFlush, getBufferSize(), advertiseURI, layout, null); @@ -112,7 +111,7 @@ public B setAdvertiseURI(final String advertiseURI) { private Object advertisement; private final Advertiser advertiser; - private RandomAccessFileAppender(final String name, final Layout layout, + private RandomAccessFileAppender(final String name, final Layout layout, final Filter filter, final RandomAccessFileManager manager, final String filename, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileManager.java index ba2c52b4128..46b21b83013 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileManager.java @@ -20,7 +20,6 @@ import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; -import java.io.Serializable; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; @@ -29,7 +28,6 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.util.FileUtils; -import org.apache.logging.log4j.core.util.NullOutputStream; /** * Extends OutputStreamManager but instead of using a buffered output stream, @@ -46,7 +44,7 @@ public class RandomAccessFileManager extends OutputStreamManager { protected RandomAccessFileManager(final LoggerContext loggerContext, final RandomAccessFile file, final String fileName, final OutputStream os, final int bufferSize, final String advertiseURI, - final Layout layout, final boolean writeHeader) { + final Layout layout, final boolean writeHeader) { super(loggerContext, os, fileName, false, layout, writeHeader, ByteBuffer.wrap(new byte[bufferSize])); this.randomAccessFile = file; this.advertiseURI = advertiseURI; @@ -68,7 +66,7 @@ protected RandomAccessFileManager(final LoggerContext loggerContext, final Rando */ public static RandomAccessFileManager getFileManager(final String fileName, final boolean append, final boolean immediateFlush, final int bufferSize, final String advertiseURI, - final Layout layout, final Configuration configuration) { + final Layout layout, final Configuration configuration) { return narrow(RandomAccessFileManager.class, getManager(fileName, new FactoryData(append, immediateFlush, bufferSize, advertiseURI, layout, configuration), FACTORY)); } @@ -78,7 +76,7 @@ public static RandomAccessFileManager getFileManager(final String fileName, fina * @return {@link Boolean#FALSE}. * @deprecated end-of-batch on the event is used instead. */ - @Deprecated + @Deprecated public Boolean isEndOfBatch() { return Boolean.FALSE; } @@ -160,7 +158,7 @@ private static class FactoryData extends ConfigurationFactoryData { private final boolean immediateFlush; private final int bufferSize; private final String advertiseURI; - private final Layout layout; + private final Layout layout; /** * Constructor. @@ -170,7 +168,7 @@ private static class FactoryData extends ConfigurationFactoryData { * @param configuration The configuration. */ public FactoryData(final boolean append, final boolean immediateFlush, final int bufferSize, - final String advertiseURI, final Layout layout, final Configuration configuration) { + final String advertiseURI, final Layout layout, final Configuration configuration) { super(configuration); this.append = append; this.immediateFlush = immediateFlush; @@ -201,7 +199,7 @@ public RandomAccessFileManager createManager(final String name, final FactoryDat } final boolean writeHeader = !data.append || !file.exists(); - final OutputStream os = NullOutputStream.getInstance(); + final OutputStream os = OutputStream.nullOutputStream(); final RandomAccessFile raf; try { FileUtils.makeParentDirs(file); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java index 92d1b2153aa..a619962f3d9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.zip.Deflater; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -34,12 +39,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.zip.Deflater; - /** * An appender that writes to files and can roll over at intervals. */ @@ -139,7 +138,7 @@ public RollingFileAppender build() { return null; } - final Layout layout = getOrCreateLayout(); + final Layout layout = getOrCreateLayout(); final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, append, isBufferedIo, policy, strategy, advertiseUri, layout, bufferSize, isImmediateFlush(), createOnDemand, filePermissions, fileOwner, fileGroup, getConfiguration()); @@ -268,7 +267,7 @@ public B setFileGroup(final String fileGroup) { private Object advertisement; private final Advertiser advertiser; - private RollingFileAppender(final String name, final Layout layout, final Filter filter, + private RollingFileAppender(final String name, final Layout layout, final Filter filter, final RollingFileManager manager, final String fileName, final String filePattern, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) { super(name, layout, filter, ignoreExceptions, immediateFlush, null, manager); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java index bd88dfcbab3..e174791d63c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.zip.Deflater; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -33,12 +38,6 @@ import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.zip.Deflater; - /** * An appender that writes to random access files and can roll over at * intervals. @@ -122,7 +121,7 @@ public RollingRandomAccessFileAppender build() { return null; } - final Layout layout = getOrCreateLayout(); + final Layout layout = getOrCreateLayout(); final boolean immediateFlush = isImmediateFlush(); final int bufferSize = getBufferSize(); @@ -197,7 +196,7 @@ public B setFileGroup(final String fileGroup) { private final Object advertisement; private final Advertiser advertiser; - private RollingRandomAccessFileAppender(final String name, final Layout layout, + private RollingRandomAccessFileAppender(final String name, final Layout layout, final Filter filter, final RollingRandomAccessFileManager manager, final String fileName, final String filePattern, final boolean ignoreExceptions, final boolean immediateFlush, final int bufferSize, final Advertiser advertiser) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java index 907e0ecf227..4b41c117311 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; @@ -38,11 +42,6 @@ import org.apache.logging.log4j.plugins.validation.constraints.ValidHost; import org.apache.logging.log4j.plugins.validation.constraints.ValidPort; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - /** * An Appender that delivers events over socket connections. Supports both TCP and UDP. */ @@ -197,7 +196,7 @@ public static class Builder extends AbstractBuilder public SocketAppender build() { boolean immediateFlush = isImmediateFlush(); final boolean bufferedIo = isBufferedIo(); - final Layout layout = getLayout(); + final Layout layout = getLayout(); if (layout == null) { AbstractLifeCycle.LOGGER.error("No layout provided for SocketAppender"); return null; @@ -231,7 +230,7 @@ public static Builder newBuilder() { private final Object advertisement; private final Advertiser advertiser; - protected SocketAppender(final String name, final Layout layout, final Filter filter, + protected SocketAppender(final String name, final Layout layout, final Filter filter, final AbstractSocketManager manager, final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) { super(name, layout, filter, ignoreExceptions, immediateFlush, null, manager); @@ -266,7 +265,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) { */ protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host, final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, - final int reconnectDelayMillis, final boolean immediateFail, final Layout layout, + final int reconnectDelayMillis, final boolean immediateFail, final Layout layout, final int bufferSize, final SocketOptions socketOptions) { if (protocol == Protocol.TCP && sslConfig != null) { // Upgrade TCP to SSL if an SSL config is specified. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java index 03525b31470..81b5d108bbd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.Serializable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -32,7 +31,7 @@ import org.apache.logging.log4j.core.net.Facility; import org.apache.logging.log4j.core.net.Protocol; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; @@ -110,7 +109,7 @@ public SyslogAppender build() { final SslConfiguration sslConfiguration = getSslConfiguration(); final boolean useTlsMessageFormat = sslConfiguration != null || protocol == Protocol.SSL; final Configuration configuration = getConfiguration(); - Layout layout = getLayout(); + Layout layout = getLayout(); if (layout == null) { layout = RFC5424.equalsIgnoreCase(format) ? new Rfc5424Layout.Rfc5424LayoutBuilder() @@ -148,7 +147,7 @@ public SyslogAppender build() { return null; } final AbstractSocketManager manager = createSocketManager(name, protocol, getHost(), getPort(), getConnectTimeoutMillis(), - sslConfiguration, getReconnectDelayMillis(), getImmediateFail(), layout, Constants.ENCODER_BYTE_BUFFER_SIZE, null); + sslConfiguration, getReconnectDelayMillis(), getImmediateFail(), layout, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize(), null); return new SyslogAppender(name, layout, getFilter(), isIgnoreExceptions(), isImmediateFlush(), manager, getAdvertise() ? configuration.getAdvertiser() : null); @@ -327,7 +326,7 @@ public B setLoggerFields(final LoggerFields[] loggerFields) { protected static final String RFC5424 = "RFC5424"; - protected SyslogAppender(final String name, final Layout layout, final Filter filter, + protected SyslogAppender(final String name, final Layout layout, final Filter filter, final boolean ignoreExceptions, final boolean immediateFlush, final AbstractSocketManager manager, final Advertiser advertiser) { super(name, layout, filter, manager, ignoreExceptions, immediateFlush, advertiser); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java index 55f21bdbf37..a5dcf6dd803 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java @@ -16,18 +16,17 @@ */ package org.apache.logging.log4j.core.appender; +import java.io.Writer; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.StringLayout; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.CloseShieldWriter; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginFactory; -import java.io.Writer; - /** * Appends log events to a {@link Writer}. */ @@ -47,8 +46,7 @@ public static class Builder> extends AbstractAppender.Build @Override public WriterAppender build() { - final StringLayout layout = (StringLayout) getLayout(); - final StringLayout actualLayout = layout != null ? layout : PatternLayout.createDefaultLayout(); + final StringLayout actualLayout = (StringLayout) getOrCreateLayout(); return new WriterAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout), isIgnoreExceptions(), getPropertyArray()); } @@ -107,39 +105,6 @@ public WriterManager createManager(final String name, final FactoryData data) { private static final WriterManagerFactory factory = new WriterManagerFactory(); - /** - * Creates a WriterAppender. - * - * @param layout - * The layout to use or null to get the default layout. - * @param filter - * The Filter or null. - * @param target - * The target Writer - * @param follow - * If true will follow changes to the underlying output stream. - * Use false as the default. - * @param name - * The name of the Appender (required). - * @param ignore - * If {@code "true"} (default) exceptions encountered when - * appending events are logged; otherwise they are propagated to - * the caller. Use true as the default. - * @return The ConsoleAppender. - */ - @PluginFactory - public static WriterAppender createAppender(StringLayout layout, final Filter filter, final Writer target, - final String name, final boolean follow, final boolean ignore) { - if (name == null) { - LOGGER.error("No name provided for WriterAppender"); - return null; - } - if (layout == null) { - layout = PatternLayout.createDefaultLayout(); - } - return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignore, Property.EMPTY_ARRAY); - } - private static WriterManager getManager(final Writer target, final boolean follow, final StringLayout layout) { final Writer writer = new CloseShieldWriter(target); final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.' diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java index 62bd192b195..364b7356cb0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender.db; -import java.io.Serializable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -63,7 +62,7 @@ public static class Builder> extends AbstractAppender.Build * @param manager The matching {@link AbstractDatabaseManager} implementation. */ protected AbstractDatabaseAppender(final String name, final Filter filter, - final Layout layout, final boolean ignoreExceptions, final Property[] properties, final T manager) { + final Layout layout, final boolean ignoreExceptions, final Property[] properties, final T manager) { super(name, filter, layout, ignoreExceptions, properties); this.manager = manager; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java index 870f614d1c3..027a611af55 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java @@ -14,7 +14,6 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.appender.db; import java.io.Flushable; @@ -38,7 +37,7 @@ public abstract class AbstractDatabaseManager extends AbstractManager implements */ protected abstract static class AbstractFactoryData { private final int bufferSize; - private final Layout layout; + private final Layout layout; /** * Constructs the base factory data. @@ -46,7 +45,7 @@ protected abstract static class AbstractFactoryData { * @param bufferSize The size of the buffer. * @param layout The appender-level layout */ - protected AbstractFactoryData(final int bufferSize, final Layout layout) { + protected AbstractFactoryData(final int bufferSize, final Layout layout) { this.bufferSize = bufferSize; this.layout = layout; } @@ -65,7 +64,7 @@ public int getBufferSize() { * * @return the layout. */ - public Layout getLayout() { + public Layout getLayout() { return layout; } } @@ -91,7 +90,7 @@ protected static buffer; private final int bufferSize; - private final Layout layout; + private final Layout layout; private boolean running; /** * Instantiates the base manager. @@ -112,7 +111,7 @@ protected AbstractDatabaseManager(final String name, final int bufferSize) { * @param layout the Appender-level layout. * @param bufferSize The size of the log event buffer. */ - protected AbstractDatabaseManager(final String name, final int bufferSize, final Layout layout) { + protected AbstractDatabaseManager(final String name, final int bufferSize, final Layout layout) { super(null, name); this.bufferSize = bufferSize; this.buffer = new ArrayList<>(bufferSize + 1); @@ -246,7 +245,7 @@ public final String toString() { * @param event The event to write to the database. * @param serializable Serializable event */ - public final synchronized void write(final LogEvent event, final Serializable serializable) { + public final synchronized void write(final LogEvent event, final Object serializable) { if (isBuffered()) { buffer(event); } else { @@ -260,9 +259,9 @@ public final synchronized void write(final LogEvent event, final Serializable se * * @param event The event to write to the database. */ - protected abstract void writeInternal(LogEvent event, Serializable serializable); + protected abstract void writeInternal(LogEvent event, Object serializable); - protected void writeThrough(final LogEvent event, final Serializable serializable) { + protected void writeThrough(final LogEvent event, final Object serializable) { this.connectAndStart(); try { this.writeInternal(event, serializable); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java index 212c2e37fbc..0088ff39585 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java @@ -28,8 +28,6 @@ import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import java.io.Serializable; - /** * This Appender writes logging events to a NoSQL database using a configured NoSQL provider. It requires * implementations of {@link NoSqlObject}, {@link NoSqlConnection}, and {@link NoSqlProvider} to "know" how to write @@ -116,7 +114,7 @@ public static > B newBuilder() { private final String description; - private NoSqlAppender(final String name, final Filter filter, final Layout layout, + private NoSqlAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, final Property[] properties, final NoSqlDatabaseManager manager) { super(name, filter, layout, ignoreExceptions, properties, manager); this.description = this.getName() + "{ manager=" + this.getManager() + " }"; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java index 3f1782ceebe..0df6aba881c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java @@ -16,8 +16,6 @@ */ package org.apache.logging.log4j.core.appender.nosql; -import java.io.Serializable; - import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; @@ -68,7 +66,7 @@ protected void connectAndStart() { } @Override - protected void writeInternal(final LogEvent event, final Serializable serializable) { + protected void writeInternal(final LogEvent event, final Object serializable) { if (!this.isRunning() || this.connection == null || this.connection.isClosed()) { throw new AppenderLoggingException( "Cannot write logging event; NoSQL manager not connected to the database."); @@ -176,7 +174,7 @@ protected boolean commitAndClose() { // also, all our NoSQL drivers use internal connection pooling and provide clients, not connections. // thus, we should not be closing the client until shutdown as NoSQL is very different from SQL. // see LOG4J2-591 and LOG4J2-676 - return true; + return true; } private NoSqlObject[] convertStackTrace(final StackTraceElement[] stackTrace) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicy.java index 4c171482f9b..d58c50e937d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/LoggerNameLevelRewritePolicy.java @@ -16,9 +16,12 @@ */ package org.apache.logging.log4j.core.appender.rewrite; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; @@ -26,10 +29,6 @@ import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - /** * Rewrites log event levels for a given logger name. * @@ -86,8 +85,9 @@ public LogEvent rewrite(final LogEvent event) { if (newLevel == null || newLevel == sourceLevel) { return event; } - final LogEvent result = new Log4jLogEvent.Builder(event).setLevel(newLevel).build(); - return result; + return LogEvent.builderFrom(event) + .setLevel(newLevel) + .build(); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java index 32fd1fccf9a..fef368d1ec9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java @@ -16,9 +16,11 @@ */ package org.apache.logging.log4j.core.appender.rewrite; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.message.Message; @@ -28,9 +30,7 @@ import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.status.StatusLogger; - -import java.util.HashMap; -import java.util.Map; +import org.apache.logging.log4j.util.Cast; /** * This policy modifies events by replacing or possibly adding keys and values to the MapMessage. @@ -42,7 +42,7 @@ public final class MapRewritePolicy implements RewritePolicy { /** * Allow subclasses access to the status logger without creating another instance. */ - protected static final Logger LOGGER = StatusLogger.getLogger(); + private static final Logger LOGGER = StatusLogger.getLogger(); private final Map map; @@ -62,18 +62,18 @@ private MapRewritePolicy(final Map map, final Mode mode) { @Override public LogEvent rewrite(final LogEvent source) { final Message msg = source.getMessage(); - if (msg == null || !(msg instanceof MapMessage)) { + if (!(msg instanceof MapMessage)) { return source; } - @SuppressWarnings("unchecked") - final MapMessage mapMsg = (MapMessage) msg; + final MapMessage mapMsg = Cast.cast(msg); final Map newMap = new HashMap<>(mapMsg.getData()); switch (mode) { case Add: { newMap.putAll(map); break; } + case Update: default: { for (final Map.Entry entry : map.entrySet()) { if (newMap.containsKey(entry.getKey())) { @@ -83,7 +83,7 @@ public LogEvent rewrite(final LogEvent source) { } } final Message message = mapMsg.newInstance(newMap); - return new Log4jLogEvent.Builder(source).setMessage(message).build(); + return LogEvent.builderFrom(source).setMessage(message).toImmutable(); } /** @@ -130,7 +130,7 @@ public String toString() { public static MapRewritePolicy createPolicy( @PluginAttribute final String mode, @PluginElement("KeyValuePair") final KeyValuePair[] pairs) { - Mode op = mode == null ? op = Mode.Add : Mode.valueOf(mode); + Mode op = mode == null ? Mode.Add : Mode.valueOf(mode); if (pairs == null || pairs.length == 0) { LOGGER.error("keys and values must be specified for the MapRewritePolicy"); return null; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java index 112b2ee625e..dc7861705be 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/PropertiesRewritePolicy.java @@ -16,25 +16,24 @@ */ package org.apache.logging.log4j.core.appender.rewrite; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Factory; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginElement; -import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.StringMap; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * This policy modifies events by replacing or possibly adding keys and values to the MapMessage. */ @@ -47,15 +46,18 @@ public final class PropertiesRewritePolicy implements RewritePolicy { */ protected static final Logger LOGGER = StatusLogger.getLogger(); + private final ContextDataFactory contextDataFactory; + private final StrSubstitutor strSubstitutor; private final Map properties; - private final Configuration config; - private PropertiesRewritePolicy(final Configuration config, final List props) { - this.config = config; + private PropertiesRewritePolicy(final ContextDataFactory contextDataFactory, final StrSubstitutor strSubstitutor, + final List props) { + this.contextDataFactory = contextDataFactory; + this.strSubstitutor = strSubstitutor; this.properties = new HashMap<>(props.size()); for (final Property property : props) { - final Boolean interpolate = Boolean.valueOf(property.getValue().contains("${")); + final boolean interpolate = property.getValue().contains("${"); properties.put(property, interpolate); } } @@ -68,14 +70,16 @@ private PropertiesRewritePolicy(final Configuration config, final List */ @Override public LogEvent rewrite(final LogEvent source) { - final StringMap newContextData = ContextDataFactory.createContextData(source.getContextData()); + final StringMap newContextData = contextDataFactory.createContextData(source.getContextData()); for (final Map.Entry entry : properties.entrySet()) { final Property prop = entry.getKey(); - newContextData.putValue(prop.getName(), entry.getValue().booleanValue() ? - config.getStrSubstitutor().replace(prop.getValue()) : prop.getValue()); + newContextData.putValue(prop.getName(), entry.getValue() ? + strSubstitutor.replace(prop.getValue()) : prop.getValue()); } - return new Log4jLogEvent.Builder(source).setContextData(newContextData).build(); + return LogEvent.builderFrom(source) + .setContextData(newContextData) + .build(); } @Override @@ -95,20 +99,48 @@ public String toString() { return sb.toString(); } - /** - * Creates a PropertiesRewritePolicy. - * @param config The Configuration. - * @param props key/value pairs for the new keys and values. - * @return The PropertiesRewritePolicy. - */ - @PluginFactory - public static PropertiesRewritePolicy createPolicy(@PluginConfiguration final Configuration config, - @PluginElement("Properties") final Property[] props) { - if (props == null || props.length == 0) { - LOGGER.error("Properties must be specified for the PropertiesRewritePolicy"); - return null; + @Factory + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder implements Supplier { + private ContextDataFactory contextDataFactory; + private StrSubstitutor strSubstitutor; + private List properties; + + public ContextDataFactory getContextDataFactory() { + return contextDataFactory; + } + + @Inject + public Builder setContextDataFactory(final ContextDataFactory contextDataFactory) { + this.contextDataFactory = contextDataFactory; + return this; + } + + public StrSubstitutor getStrSubstitutor() { + return strSubstitutor; + } + + @Inject + public Builder setStrSubstitutor(final StrSubstitutor strSubstitutor) { + this.strSubstitutor = strSubstitutor; + return this; + } + + public List getProperties() { + return properties; + } + + public Builder setProperties(@PluginElement("Properties") final Property[] props) { + properties = List.of(props); + return this; + } + + @Override + public PropertiesRewritePolicy get() { + return new PropertiesRewritePolicy(contextDataFactory, strSubstitutor, properties); } - final List properties = Arrays.asList(props); - return new PropertiesRewritePolicy(config, properties); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java index e508ece4659..100514460b6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java @@ -16,9 +16,14 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.pattern.ArrayPatternConverter; import org.apache.logging.log4j.core.pattern.DatePatternConverter; @@ -28,12 +33,6 @@ import org.apache.logging.log4j.core.pattern.PatternParser; import org.apache.logging.log4j.status.StatusLogger; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - /** * Parses the rollover pattern. */ @@ -238,9 +237,9 @@ public long getNextTime(final long currentMillis, final int increment, final boo public void updateTime() { if (nextFileTime != 0 || !isTimeBased) { - prevFileTime = nextFileTime; - currentFileTime = 0; - } + prevFileTime = nextFileTime; + currentFileTime = 0; + } } private long debugGetNextTime(final long nextTime) { @@ -293,12 +292,12 @@ public final void formatFileName(final StrSubstitutor subst, final StringBuilder final Object obj) { // LOG4J2-628: we deliberately use System time, not the log4j.Clock time // for creating the file name of rolled-over files. - LOGGER.debug("Formatting file name. useCurrentTime={}, currentFileTime={}, prevFileTime={}, nextFileTime={}", - useCurrentTime, currentFileTime, prevFileTime, nextFileTime); - final long time = useCurrentTime ? currentFileTime != 0 ? currentFileTime : System.currentTimeMillis() : + LOGGER.debug("Formatting file name. useCurrentTime={}, currentFileTime={}, prevFileTime={}, nextFileTime={}", + useCurrentTime, currentFileTime, prevFileTime, nextFileTime); + final long time = useCurrentTime ? currentFileTime != 0 ? currentFileTime : System.currentTimeMillis() : prevFileTime != 0 ? prevFileTime : System.currentTimeMillis(); formatFileName(buf, new Date(time), obj); - final LogEvent event = new Log4jLogEvent.Builder().setTimeMillis(time).build(); + final LogEvent event = LogEvent.builder().setTimeMillis(time).toImmutable(); final String fileName = subst.replace(event, buf); buf.setLength(0); buf.append(fileName); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java index f7d9dcc07bc..8038a4c926a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java @@ -20,7 +20,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; @@ -45,8 +44,8 @@ import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction; import org.apache.logging.log4j.core.appender.rolling.action.Action; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.core.util.Log4jThreadFactory; /** @@ -92,11 +91,11 @@ public class RollingFileManager extends FileManager { protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os, final boolean append, final boolean createOnDemand, final long size, final long initialTime, final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy, - final String advertiseURI, final Layout layout, + final String advertiseURI, final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final boolean writeHeader, final ByteBuffer buffer) { super(loggerContext, fileName != null ? fileName : pattern, os, append, false, createOnDemand, - advertiseURI, layout, filePermissions, fileOwner, fileGroup, writeHeader, buffer); + advertiseURI, layout, filePermissions, fileOwner, fileGroup, writeHeader, buffer); this.size = size; this.initialTime = initialTime; this.triggeringPolicy = triggeringPolicy; @@ -150,7 +149,7 @@ public void initialize() { */ public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append, final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy, - final String advertiseURI, final Layout layout, final int bufferSize, + final String advertiseURI, final Layout layout, final int bufferSize, final boolean immediateFlush, final boolean createOnDemand, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { @@ -302,12 +301,12 @@ public boolean releaseSub(final long timeout, final TimeUnit timeUnit) { return status; } - public synchronized void rollover(final long prevFileTime, final long prevRollTime) { + public synchronized void rollover(final long prevFileTime, final long prevRollTime) { LOGGER.debug("Rollover PrevFileTime: {}, PrevRollTime: {}", prevFileTime, prevRollTime); - getPatternProcessor().setPrevFileTime(prevFileTime); - getPatternProcessor().setCurrentFileTime(prevRollTime); - rollover(); - } + getPatternProcessor().setPrevFileTime(prevFileTime); + getPatternProcessor().setCurrentFileTime(prevRollTime); + rollover(); + } public synchronized void rollover() { if (!hasOutputStream() && !isCreateOnDemand() && !isDirectWrite()) { @@ -548,7 +547,7 @@ private static class FactoryData extends ConfigurationFactoryData { private final TriggeringPolicy policy; private final RolloverStrategy strategy; private final String advertiseURI; - private final Layout layout; + private final Layout layout; private final String filePermissions; private final String fileOwner; private final String fileGroup; @@ -570,7 +569,7 @@ private static class FactoryData extends ConfigurationFactoryData { */ public FactoryData(final String fileName, final String pattern, final boolean append, final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, - final Layout layout, final int bufferSize, final boolean immediateFlush, + final Layout layout, final int bufferSize, final boolean immediateFlush, final boolean createOnDemand, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { super(configuration); @@ -675,7 +674,7 @@ public RollingFileManager createManager(final String name, final FactoryData dat } try { - final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE; + final int actualSize = data.bufferedIO ? data.bufferSize : GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize(); final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]); final OutputStream os = data.createOnDemand || data.fileName == null ? null : new FileOutputStream(data.fileName, data.append); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java index 9be7e44d9da..12611de51d3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java @@ -20,7 +20,6 @@ import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.file.Paths; @@ -31,7 +30,6 @@ import org.apache.logging.log4j.core.appender.ManagerFactory; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.util.FileUtils; -import org.apache.logging.log4j.core.util.NullOutputStream; /** * Extends RollingFileManager but instead of using a buffered output stream, this class uses a {@code ByteBuffer} and a @@ -54,7 +52,7 @@ public RollingRandomAccessFileManager(final LoggerContext loggerContext, final R final String fileName, final String pattern, final OutputStream os, final boolean append, final boolean immediateFlush, final int bufferSize, final long initialTime, final long time, final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, - final Layout layout, + final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final boolean writeHeader) { super(loggerContext, fileName, pattern, os, append, false, initialTime, time, policy, strategy, advertiseURI, layout, @@ -88,7 +86,7 @@ protected void writeHeader() { public static RollingRandomAccessFileManager getRollingRandomAccessFileManager(final String fileName, final String filePattern, final boolean isAppend, final boolean immediateFlush, final int bufferSize, final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, - final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, + final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { if (strategy instanceof DirectWriteRolloverStrategy && fileName != null) { LOGGER.error("The fileName attribute must not be specified with the DirectWriteRolloverStrategy"); @@ -244,7 +242,7 @@ public RollingRandomAccessFileManager createManager(final String name, final Fac final boolean writeHeader = !data.append || file == null || !file.exists(); final RollingRandomAccessFileManager rrm = new RollingRandomAccessFileManager(data.getLoggerContext(), raf, name, data.pattern, - NullOutputStream.getInstance(), data.append, data.immediateFlush, data.bufferSize, size, initialTime, data.policy, + OutputStream.nullOutputStream(), data.append, data.immediateFlush, data.bufferSize, size, initialTime, data.policy, data.strategy, data.advertiseURI, data.layout, data.filePermissions, data.fileOwner, data.fileGroup, writeHeader); if (rrm.isAttributeViewEnabled()) { rrm.defineAttributeView(file.toPath()); @@ -265,7 +263,7 @@ private static class FactoryData extends ConfigurationFactoryData { private final TriggeringPolicy policy; private final RolloverStrategy strategy; private final String advertiseURI; - private final Layout layout; + private final Layout layout; private final String filePermissions; private final String fileOwner; private final String fileGroup; @@ -289,7 +287,7 @@ private static class FactoryData extends ConfigurationFactoryData { */ public FactoryData(final String fileName, final String pattern, final boolean append, final boolean immediateFlush, final int bufferSize, final TriggeringPolicy policy, final RolloverStrategy strategy, - final String advertiseURI, final Layout layout, + final String advertiseURI, final Layout layout, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { super(configuration); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java index bb68d907649..53d0988e2b1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.appender.rolling; +import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LogEvent; /** @@ -25,7 +26,7 @@ * * @see AbstractTriggeringPolicy */ -public interface TriggeringPolicy /* TODO 3.0: extends LifeCycle */ { +public interface TriggeringPolicy extends LifeCycle { /** * Initializes this triggering policy. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java index 6e48df121bc..d46a5ec91ef 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java @@ -16,9 +16,16 @@ */ package org.apache.logging.log4j.core.appender.rolling.action; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.time.Clock; -import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; @@ -27,14 +34,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.status.StatusLogger; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; - /** * PathCondition that accepts paths that are older than the specified duration. */ @@ -50,7 +49,7 @@ public final class IfLastModified implements PathCondition { private IfLastModified(final Duration age, final PathCondition[] nestedConditions, final Clock clock) { this.age = Objects.requireNonNull(age, "age"); this.nestedConditions = PathCondition.copy(nestedConditions); - this.clock = clock; + this.clock = Objects.requireNonNull(clock, "clock"); } public Duration getAge() { @@ -98,18 +97,6 @@ public String toString() { return "IfLastModified(age=" + age + nested + ")"; } - /** - * Create an IfLastModified condition. - * - * @param age The path age that is accepted by this condition. Must be a valid Duration. - * @param nestedConditions nested conditions to evaluate if this condition accepts a path - * @return An IfLastModified condition. - */ - @Deprecated(since = "3.0.0", forRemoval = true) - public static IfLastModified createAgeCondition(final Duration age, final PathCondition... nestedConditions) { - return newBuilder().setAge(age).setNestedConditions(nestedConditions).get(); - } - @PluginFactory public static Builder newBuilder() { return new Builder(); @@ -138,9 +125,6 @@ public Builder setClock(final Clock clock) { @Override public IfLastModified get() { - if (clock == null) { - clock = ClockFactory.getClock(); - } return new IfLastModified(age, nestedConditions, clock); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java index e314e6cf9c5..6a35a3bf3a3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java @@ -35,8 +35,10 @@ import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.ReusableMessage; +import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StackLocatorUtil; import org.apache.logging.log4j.util.StringMap; @@ -71,11 +73,11 @@ public class AsyncLogger extends Logger implements EventTranslatorVararg threadLocalTranslator = new ThreadLocal<>(); private final AsyncLoggerDisruptor loggerDisruptor; + private final ThreadNameCachingStrategy threadNameCachingStrategy; private volatile boolean includeLocation; // reconfigurable private volatile NanoClock nanoClock; // reconfigurable @@ -88,15 +90,17 @@ public class AsyncLogger extends Logger implements EventTranslatorVararg> extends LoggerConfig.Builder appenders, final Filter filter, final Level level, final boolean additive, final Property[] properties, final Configuration config, - final boolean includeLocation, final LogEventFactory logEventFactory) { + final boolean includeLocation, final LogEventFactory logEventFactory, + final PropertyResolver propertyResolver) { super(name, appenders, filter, level, additive, properties, config, - includeLocation, logEventFactory); + includeLocation, logEventFactory, propertyResolver); delegate = config.getAsyncLoggerConfigDelegate(); delegate.setLogEventFactory(getLogEventFactory()); } @@ -211,76 +214,6 @@ public RingBufferAdmin createRingBufferAdmin(final String contextName) { return delegate.createRingBufferAdmin(contextName, getName()); } - /** - * Factory method to create a LoggerConfig. - * - * @param additivity True if additive, false otherwise. - * @param levelName The Level to be associated with the Logger. - * @param loggerName The name of the Logger. - * @param includeLocation "true" if location should be passed downstream - * @param refs An array of Appender names. - * @param properties Properties to pass to the Logger. - * @param config The Configuration. - * @param filter A Filter. - * @return A new LoggerConfig. - * @deprecated use {@link #createLogger(boolean, Level, String, String, AppenderRef[], Property[], Configuration, Filter)} - */ - @Deprecated - public static LoggerConfig createLogger( - final String additivity, - final String levelName, - final String loggerName, - final String includeLocation, - final AppenderRef[] refs, - final Property[] properties, - final Configuration config, - final Filter filter) { - if (loggerName == null) { - LOGGER.error("Loggers cannot be configured without a name"); - return null; - } - - final List appenderRefs = Arrays.asList(refs); - Level level; - try { - level = Level.toLevel(levelName, Level.ERROR); - } catch (final Exception ex) { - LOGGER.error( - "Invalid Log level specified: {}. Defaulting to Error", - levelName); - level = Level.ERROR; - } - final String name = loggerName.equals(LoggerConfig.ROOT) ? Strings.EMPTY : loggerName; - final boolean additive = Booleans.parseBoolean(additivity, true); - - return new AsyncLoggerConfig(name, appenderRefs, filter, level, - additive, properties, config, includeLocation(includeLocation), - config.getComponent(LogEventFactory.KEY)); - } - - /** - * Factory method to create a LoggerConfig. - * - * @param additivity True if additive, false otherwise. - * @param level The Level to be associated with the Logger. - * @param loggerName The name of the Logger. - * @param includeLocation "true" if location should be passed downstream - * @param refs An array of Appender names. - * @param properties Properties to pass to the Logger. - * @param config The Configuration. - * @param filter A Filter. - * @return A new LoggerConfig. - * @since 3.0 - */ - @Deprecated - public static LoggerConfig createLogger( - final boolean additivity, final Level level, final String loggerName, final String includeLocation, - final AppenderRef[] refs, final Property[] properties, final Configuration config, final Filter filter) { - final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; - return new AsyncLoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config, - includeLocation(includeLocation), config.getComponent(LogEventFactory.KEY)); - } - // Note: for asynchronous loggers, includeLocation default is FALSE protected static boolean includeLocation(final String includeLocationConfigValue) { return Boolean.parseBoolean(includeLocationConfigValue); @@ -291,34 +224,30 @@ protected static boolean includeLocation(final String includeLocationConfigValue */ @Configurable(printObject = true) @Plugin("asyncRoot") - public static class RootLogger extends LoggerConfig { + public static class RootLogger extends AsyncLoggerConfig { + private RootLogger(final List appenders, final Filter filter, + final Level level, final boolean additive, final Property[] properties, + final Configuration config, final boolean includeLocation, + final LogEventFactory logEventFactory, final PropertyResolver propertyResolver) { + super(LogManager.ROOT_LOGGER_NAME, appenders, filter, level, additive, properties, + config, includeLocation, logEventFactory, propertyResolver); + } @PluginFactory public static > B newAsyncRootBuilder() { return new Builder().asBuilder(); } - public static class Builder> extends RootLogger.Builder { + public static class Builder> extends LoggerConfig.RootLogger.Builder { @Override public LoggerConfig build() { LevelAndRefs container = LoggerConfig.getLevelAndRefs(getLevel(), getRefs(), getLevelAndRefs(), getConfig()); - return new AsyncLoggerConfig(LogManager.ROOT_LOGGER_NAME, container.refs, getFilter(), container.level, - isAdditivity(), getProperties(), getConfig(), - AsyncLoggerConfig.includeLocation(getIncludeLocation()), getLogEventFactory()); + return new AsyncLoggerConfig.RootLogger(container.refs, getFilter(), container.level, + isAdditivity(), getProperties(), getConfig(), includeLocation(getIncludeLocation()), + getLogEventFactory(), getPropertyResolver()); } } - - @Deprecated - public static LoggerConfig createLogger(final String additivity, final Level level, final String includeLocation, - final AppenderRef[] refs, final Property[] properties, final Configuration config, final Filter filter) { - final List appenderRefs = Arrays.asList(refs); - final Level actualLevel = level == null ? Level.ERROR : level; - final boolean additive = Booleans.parseBoolean(additivity, true); - return new AsyncLoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive, - properties, config, AsyncLoggerConfig.includeLocation(includeLocation), - config.getComponent(LogEventFactory.KEY)); - } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java index f40c90b8e8c..338eea12319 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java @@ -16,22 +16,26 @@ */ package org.apache.logging.log4j.core.async; +import java.util.Optional; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.impl.LogEventFactory; import org.apache.logging.log4j.core.impl.MutableLogEvent; import org.apache.logging.log4j.core.impl.ReusableLogEventFactory; import org.apache.logging.log4j.core.jmx.RingBufferAdmin; -import org.apache.logging.log4j.core.util.Log4jThread; import org.apache.logging.log4j.core.util.Log4jThreadFactory; import org.apache.logging.log4j.core.util.Throwables; import org.apache.logging.log4j.message.ReusableMessage; +import org.apache.logging.log4j.plugins.Inject; import com.lmax.disruptor.EventFactory; import com.lmax.disruptor.EventTranslatorTwoArg; @@ -167,13 +171,20 @@ private void notifyIntermediateProgress(final long sequence) { private EventFactory factory; private EventTranslatorTwoArg translator; private volatile boolean alreadyLoggedWarning; + private final DisruptorConfiguration configuration; + private final Supplier asyncQueueFullPolicySupplier; private final AsyncWaitStrategyFactory asyncWaitStrategyFactory; private WaitStrategy waitStrategy; - private final Object queueFullEnqueueLock = new Object(); + private final Lock queueFullEnqueueLock = new ReentrantLock(); - public AsyncLoggerConfigDisruptor(AsyncWaitStrategyFactory asyncWaitStrategyFactory) { - this.asyncWaitStrategyFactory = asyncWaitStrategyFactory; // may be null + @Inject + public AsyncLoggerConfigDisruptor(final DisruptorConfiguration configuration, + final Supplier asyncQueueFullPolicySupplier, + final Optional optionalAsyncWaitStrategyFactory) { + this.configuration = configuration; + this.asyncQueueFullPolicySupplier = asyncQueueFullPolicySupplier; + this.asyncWaitStrategyFactory = optionalAsyncWaitStrategyFactory.orElse(null); } // package-protected for testing @@ -181,6 +192,11 @@ WaitStrategy getWaitStrategy() { return waitStrategy; } + // package-protected for testing + Disruptor getDisruptor() { + return disruptor; + } + // called from AsyncLoggerConfig constructor @Override public void setLogEventFactory(final LogEventFactory logEventFactory) { @@ -203,9 +219,8 @@ public synchronized void start() { return; } LOGGER.trace("AsyncLoggerConfigDisruptor creating new disruptor for this configuration."); - ringBufferSize = DisruptorUtil.calculateRingBufferSize(Log4jProperties.ASYNC_CONFIG_RING_BUFFER_SIZE); - waitStrategy = DisruptorUtil.createWaitStrategy( - Log4jProperties.ASYNC_CONFIG_WAIT_STRATEGY, asyncWaitStrategyFactory); + ringBufferSize = configuration.calculateRingBufferSize(Log4jProperties.ASYNC_CONFIG_RING_BUFFER_SIZE); + waitStrategy = configuration.createWaitStrategy(Log4jProperties.ASYNC_CONFIG_WAIT_STRATEGY, asyncWaitStrategyFactory); final ThreadFactory threadFactory = new Log4jThreadFactory("AsyncLoggerConfig", true, Thread.NORM_PRIORITY) { @Override @@ -215,13 +230,13 @@ public Thread newThread(final Runnable r) { return result; } }; - asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create(); + asyncQueueFullPolicy = asyncQueueFullPolicySupplier.get(); translator = mutable ? MUTABLE_TRANSLATOR : TRANSLATOR; factory = mutable ? MUTABLE_FACTORY : FACTORY; disruptor = new Disruptor<>(factory, ringBufferSize, threadFactory, ProducerType.MULTI, waitStrategy); - final ExceptionHandler errorHandler = DisruptorUtil.getAsyncLoggerConfigExceptionHandler(); + final ExceptionHandler errorHandler = configuration.getAsyncLoggerConfigExceptionHandler(); disruptor.setDefaultExceptionHandler(errorHandler); final Log4jEventWrapperHandler[] handlers = {new Log4jEventWrapperHandler()}; @@ -331,14 +346,14 @@ public void enqueueEvent(final LogEvent event, final AsyncLoggerConfig asyncLogg private LogEvent prepareEvent(final LogEvent event) { LogEvent logEvent = ensureImmutable(event); if (logEvent.getMessage() instanceof ReusableMessage) { - if (logEvent instanceof Log4jLogEvent) { - ((Log4jLogEvent) logEvent).makeMessageImmutable(); + if (logEvent instanceof ImmutableLogEvent) { + ((ImmutableLogEvent) logEvent).freezeMessage(); } else if (logEvent instanceof MutableLogEvent) { // MutableLogEvents need to be translated into the RingBuffer by the MUTABLE_TRANSLATOR. // That translator calls MutableLogEvent.initFrom to copy the event, which will makeMessageImmutable the message. if (translator != MUTABLE_TRANSLATOR) { // should not happen... // TRANSLATOR expects an immutable LogEvent - logEvent = ((MutableLogEvent) logEvent).createMemento(); + logEvent = logEvent.copy(); } } else { // custom log event, with a ReusableMessage showWarningAboutCustomLogEventWithReusableMessage(logEvent); @@ -363,8 +378,11 @@ private void showWarningAboutCustomLogEventWithReusableMessage(final LogEvent lo private void enqueue(final LogEvent logEvent, final AsyncLoggerConfig asyncLoggerConfig) { if (synchronizeEnqueueWhenQueueFull()) { - synchronized (queueFullEnqueueLock) { + queueFullEnqueueLock.lock(); + try { disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig); + } finally { + queueFullEnqueueLock.unlock(); } } else { disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig); @@ -372,14 +390,8 @@ private void enqueue(final LogEvent logEvent, final AsyncLoggerConfig asyncLogge } private boolean synchronizeEnqueueWhenQueueFull() { - return DisruptorUtil.ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL - // Background thread must never block - && backgroundThreadId != Thread.currentThread().getId() - // Threads owned by log4j are most likely to result in - // deadlocks because they generally consume events. - // This prevents deadlocks between AsyncLoggerContext - // disruptors. - && !(Thread.currentThread() instanceof Log4jThread); + return configuration.synchronizeEnqueueWhenQueueFull( + Log4jProperties.ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, backgroundThreadId); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java index ddb1c47ba49..76fb8c8d644 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java @@ -16,54 +16,65 @@ */ package org.apache.logging.log4j.core.async; +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.jmx.RingBufferAdmin; +import org.apache.logging.log4j.message.FlowMessageFactory; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.status.StatusLogger; - -import java.net.URI; -import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.util.PropertyResolver; /** * {@code LoggerContext} that creates {@code AsyncLogger} objects. */ public class AsyncLoggerContext extends LoggerContext { - private final AsyncLoggerDisruptor loggerDisruptor; - - public AsyncLoggerContext(final String name) { - super(name); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); - } - - public AsyncLoggerContext(final String name, final Object externalContext) { - super(name, externalContext); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); - } - - public AsyncLoggerContext(final String name, final Object externalContext, final URI configLocn) { - super(name, externalContext, configLocn); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); + public static Builder newAsyncBuilder() { + return new Builder(); } - public AsyncLoggerContext(final String name, final Object externalContext, final URI configLocn, final Injector injector) { - super(name, externalContext, configLocn, injector); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); + public static class Builder extends GenericBuilder implements Supplier { + @Override + public AsyncLoggerContext get() { + final PropertyResolver propertyResolver = getPropertyResolver(); + final Injector injector = getInjector(); + final DisruptorConfiguration disruptorConfiguration = injector.getInstance(DisruptorConfiguration.class); + final Supplier asyncQueueFullPolicySupplier = injector.getFactory(AsyncQueueFullPolicy.class); + final AtomicReference loggerContextRef = new AtomicReference<>(); + final Supplier asyncWaitStrategyFactorySupplier; + if (injector.hasBinding(AsyncWaitStrategyFactory.KEY)) { + asyncWaitStrategyFactorySupplier = injector.getFactory(AsyncWaitStrategyFactory.KEY); + } else { + asyncWaitStrategyFactorySupplier = () -> loggerContextRef.get() + .getConfiguration().getAsyncWaitStrategyFactory(); + } + final AsyncLoggerDisruptor disruptor = new AsyncLoggerDisruptor(getName(), disruptorConfiguration, + asyncQueueFullPolicySupplier, asyncWaitStrategyFactorySupplier); + final AsyncLoggerContext context = new AsyncLoggerContext(getName(), getKey(), getExternalContext(), + getConfigLocation(), injector, propertyResolver, getMessageFactory(), getFlowMessageFactory(), + disruptor); + loggerContextRef.set(context); + return context; + } } - public AsyncLoggerContext(final String name, final Object externalContext, final String configLocn) { - super(name, externalContext, configLocn); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); - } + private final AsyncLoggerDisruptor loggerDisruptor; - public AsyncLoggerContext( - final String name, final Object externalContext, final String configLocn, final Injector injector) { - super(name, externalContext, configLocn, injector); - loggerDisruptor = new AsyncLoggerDisruptor(name, () -> getConfiguration().getAsyncWaitStrategyFactory()); + AsyncLoggerContext(final String contextName, final String contextKey, final Object externalContext, + final URI configLocation, final Injector injector, final PropertyResolver propertyResolver, + final MessageFactory messageFactory, final FlowMessageFactory flowMessageFactory, + final AsyncLoggerDisruptor loggerDisruptor) { + super(contextName, contextKey, externalContext, configLocation, injector, propertyResolver, messageFactory, + flowMessageFactory); + this.loggerDisruptor = loggerDisruptor; } @Override @@ -73,10 +84,15 @@ protected Logger newInstance(final LoggerContext ctx, final String name, final M @Override public void setName(final String name) { - super.setName("AsyncContext[" + name + "]"); + super.setName(name); loggerDisruptor.setContextName(name); } + @Override + public void setKey(final String key) { + super.setKey("AsyncContext[" + key + ']'); + } + /* * (non-Javadoc) * diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.java index 37f585e7e0c..d5f43a8897c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.java @@ -18,13 +18,14 @@ import java.net.URI; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.config.LoggerContextNamingStrategy; import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; +import org.apache.logging.log4j.plugins.ContextScoped; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.di.Injector; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.plugins.di.SimpleScope; +import org.apache.logging.log4j.util.PropertyResolver; /** * {@code ContextSelector} that manages {@code AsyncLoggerContext} instances. @@ -34,26 +35,22 @@ @Singleton public class AsyncLoggerContextSelector extends ClassLoaderContextSelector { - /** - * Returns {@code true} if the user specified this selector as the Log4jContextSelector, to make all loggers - * asynchronous. - * - * @return {@code true} if all loggers are asynchronous, {@code false} otherwise. - */ - public static boolean isSelected() { - // FIXME(ms): this should check Injector bindings - return AsyncLoggerContextSelector.class.getName().equals( - PropertiesUtil.getProperties().getStringProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME)); - } - @Inject - public AsyncLoggerContextSelector(final Injector injector) { - super(injector); + public AsyncLoggerContextSelector(final Injector injector, final PropertyResolver resolver, + final LoggerContextNamingStrategy namingStrategy) { + super(injector, resolver, namingStrategy); } @Override - protected LoggerContext createContext(final String name, final URI configLocation, final Injector injector) { - return new AsyncLoggerContext(name, null, configLocation, injector); + protected AsyncLoggerContext createContext(final String key, final String name, final URI configLocation) { + final Injector loggerContextInjector = injector.copy(); + loggerContextInjector.registerScope(ContextScoped.class, new SimpleScope("AsyncLoggerContext; name=" + name)); + final AsyncLoggerContext.Builder builder = AsyncLoggerContext.newAsyncBuilder() + .setKey(key) + .setName(name) + .setConfigLocation(configLocation); + loggerContextInjector.injectMembers(builder); + return builder.get(); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java index 80ecc8e921f..5f680893287 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java @@ -16,9 +16,10 @@ */ package org.apache.logging.log4j.core.async; -import java.util.Objects; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; import org.apache.logging.log4j.Level; @@ -26,7 +27,6 @@ import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.jmx.RingBufferAdmin; -import org.apache.logging.log4j.core.util.Log4jThread; import org.apache.logging.log4j.core.util.Log4jThreadFactory; import org.apache.logging.log4j.core.util.Throwables; import org.apache.logging.log4j.message.Message; @@ -49,21 +49,26 @@ class AsyncLoggerDisruptor extends AbstractLifeCycle { private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50; private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200; - private final Object queueFullEnqueueLock = new Object(); + private final Lock queueFullEnqueueLock = new ReentrantLock(); private volatile Disruptor disruptor; private String contextName; + private final DisruptorConfiguration configuration; + private final Supplier asyncQueueFullPolicySupplier; private final Supplier waitStrategyFactorySupplier; private boolean useThreadLocalTranslator = true; private long backgroundThreadId; private AsyncQueueFullPolicy asyncQueueFullPolicy; - private int ringBufferSize; private WaitStrategy waitStrategy; - AsyncLoggerDisruptor(final String contextName, final Supplier waitStrategyFactorySupplier) { + AsyncLoggerDisruptor(final String contextName, final DisruptorConfiguration configuration, + final Supplier asyncQueueFullPolicySupplier, + final Supplier waitStrategyFactorySupplier) { this.contextName = contextName; - this.waitStrategyFactorySupplier = Objects.requireNonNull(waitStrategyFactorySupplier, "waitStrategyFactorySupplier"); + this.configuration = configuration; + this.asyncQueueFullPolicySupplier = asyncQueueFullPolicySupplier; + this.waitStrategyFactorySupplier = waitStrategyFactorySupplier; } // package-protected for testing @@ -79,6 +84,7 @@ public void setContextName(final String name) { contextName = name; } + // package-protected for testing Disruptor getDisruptor() { return disruptor; } @@ -102,9 +108,9 @@ public synchronized void start() { } setStarting(); LOGGER.trace("[{}] AsyncLoggerDisruptor creating new disruptor for this context.", contextName); - ringBufferSize = DisruptorUtil.calculateRingBufferSize(Log4jProperties.ASYNC_LOGGER_RING_BUFFER_SIZE); + int ringBufferSize = configuration.calculateRingBufferSize(Log4jProperties.ASYNC_LOGGER_RING_BUFFER_SIZE); AsyncWaitStrategyFactory factory = waitStrategyFactorySupplier.get(); // get factory from configuration - waitStrategy = DisruptorUtil.createWaitStrategy(Log4jProperties.ASYNC_LOGGER_WAIT_STRATEGY, factory); + waitStrategy = configuration.createWaitStrategy(Log4jProperties.ASYNC_LOGGER_WAIT_STRATEGY, factory); final ThreadFactory threadFactory = new Log4jThreadFactory("AsyncLogger[" + contextName + "]", true, Thread.NORM_PRIORITY) { @Override @@ -114,12 +120,12 @@ public Thread newThread(final Runnable r) { return result; } }; - asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create(); + asyncQueueFullPolicy = asyncQueueFullPolicySupplier.get(); - disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, ringBufferSize, threadFactory, ProducerType.MULTI, + disruptor = new Disruptor<>(RingBufferLogEvent::new, ringBufferSize, threadFactory, ProducerType.MULTI, waitStrategy); - final ExceptionHandler errorHandler = DisruptorUtil.getAsyncLoggerExceptionHandler(); + final ExceptionHandler errorHandler = configuration.getAsyncLoggerExceptionHandler(); disruptor.setDefaultExceptionHandler(errorHandler); final RingBufferLogEventHandler[] handlers = {new RingBufferLogEventHandler()}; @@ -243,8 +249,11 @@ void enqueueLogMessageWhenQueueFull(final RingBufferLogEventTranslator translato // Avoiding this and using an older reference could result in adding a log event to the disruptor after it // was shut down, which could cause the publishEvent method to hang and never return. if (synchronizeEnqueueWhenQueueFull()) { - synchronized (queueFullEnqueueLock) { + queueFullEnqueueLock.lock(); + try { disruptor.publishEvent(translator); + } finally { + queueFullEnqueueLock.unlock(); } } else { disruptor.publishEvent(translator); @@ -269,7 +278,8 @@ void enqueueLogMessageWhenQueueFull( // Avoiding this and using an older reference could result in adding a log event to the disruptor after it // was shut down, which could cause the publishEvent method to hang and never return. if (synchronizeEnqueueWhenQueueFull()) { - synchronized (queueFullEnqueueLock) { + queueFullEnqueueLock.lock(); + try { disruptor.getRingBuffer().publishEvent(translator, asyncLogger, // asyncLogger: 0 location, // location: 1 @@ -278,6 +288,8 @@ void enqueueLogMessageWhenQueueFull( marker, // 4 msg, // 5 thrown); // 6 + } finally { + queueFullEnqueueLock.unlock(); } } else { disruptor.getRingBuffer().publishEvent(translator, @@ -296,14 +308,8 @@ void enqueueLogMessageWhenQueueFull( } private boolean synchronizeEnqueueWhenQueueFull() { - return DisruptorUtil.ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL - // Background thread must never block - && backgroundThreadId != Thread.currentThread().getId() - // Threads owned by log4j are most likely to result in - // deadlocks because they generally consume events. - // This prevents deadlocks between AsyncLoggerContext - // disruptors. - && !(Thread.currentThread() instanceof Log4jThread); + return configuration.synchronizeEnqueueWhenQueueFull( + Log4jProperties.ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, backgroundThreadId); } private void logWarningOnNpeFromDisruptorPublish(final RingBufferLogEventTranslator translator) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullMessageUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullMessageUtil.java index 9c0956b6aa5..291a5550a0f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullMessageUtil.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullMessageUtil.java @@ -17,6 +17,7 @@ package org.apache.logging.log4j.core.async; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.InternalApi; /** * Consider this class private. @@ -24,6 +25,7 @@ * Logs a warning to the {@link StatusLogger} when events are logged out of order to avoid deadlocks. *

    */ +@InternalApi public final class AsyncQueueFullMessageUtil { private AsyncQueueFullMessageUtil() { // Utility Class diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java index 1e67bdb0123..d87be970844 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java @@ -16,13 +16,17 @@ */ package org.apache.logging.log4j.core.async; +import java.util.function.Supplier; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Loader; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.spi.ClassFactory; +import org.apache.logging.log4j.spi.InstanceFactory; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; /** * Creates {@link AsyncQueueFullPolicy} instances based on user-specified system properties. The {@code AsyncQueueFullPolicy} @@ -44,16 +48,31 @@ * * @since 2.6 */ -public class AsyncQueueFullPolicyFactory { +@ContextScoped +public class AsyncQueueFullPolicyFactory implements Supplier { static final String PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER = "Default"; static final String PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER = "Discard"; private static final Logger LOGGER = StatusLogger.getLogger(); + private final PropertyResolver propertyResolver; + private final ClassFactory classFactory; + private final InstanceFactory instanceFactory; + + @Inject + public AsyncQueueFullPolicyFactory( + final PropertyResolver propertyResolver, + final ClassFactory classFactory, + final InstanceFactory instanceFactory) { + this.propertyResolver = propertyResolver; + this.classFactory = classFactory; + this.instanceFactory = instanceFactory; + } + /** * Creates and returns {@link AsyncQueueFullPolicy} instances based on user-specified system properties. *

    - * Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or + * Property {@value Log4jProperties#ASYNC_LOGGER_QUEUE_FULL_POLICY} controls the routing behaviour. If this property is not specified or * has value {@code "Default"}, this method returns {@link DefaultAsyncQueueFullPolicy} objects. *

    * If this property has value {@code "Discard"}, this method returns {@link DiscardingAsyncQueueFullPolicy} objects. @@ -64,45 +83,32 @@ public class AsyncQueueFullPolicyFactory { * * @return a new AsyncQueueFullPolicy */ - public static AsyncQueueFullPolicy create() { - final String router = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY); + @Override + public AsyncQueueFullPolicy get() { + final String router = propertyResolver.getString(Log4jProperties.ASYNC_LOGGER_QUEUE_FULL_POLICY).orElse(null); if (router == null || isRouterSelected( router, DefaultAsyncQueueFullPolicy.class, PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER)) { return new DefaultAsyncQueueFullPolicy(); } if (isRouterSelected( router, DiscardingAsyncQueueFullPolicy.class, PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER)) { - return createDiscardingAsyncQueueFullPolicy(); + final Level thresholdLevel = propertyResolver.getString(Log4jProperties.ASYNC_LOGGER_DISCARD_THRESHOLD) + .map(Level::getLevel) + .orElse(Level.INFO); + LOGGER.debug("Creating custom DiscardingAsyncQueueFullPolicy(discardThreshold:{})", thresholdLevel); + return new DiscardingAsyncQueueFullPolicy(thresholdLevel); } - return createCustomRouter(router); + return classFactory.tryGetClass(router, AsyncQueueFullPolicy.class) + .flatMap(instanceFactory::tryGetInstance) + .orElseGet(DefaultAsyncQueueFullPolicy::new); } private static boolean isRouterSelected( final String propertyValue, final Class policy, final String shortPropertyValue) { - return propertyValue != null && (shortPropertyValue.equalsIgnoreCase(propertyValue) + return shortPropertyValue.equalsIgnoreCase(propertyValue) || policy.getName().equals(propertyValue) - || policy.getSimpleName().equals(propertyValue)); - } - - private static AsyncQueueFullPolicy createCustomRouter(final String router) { - try { - final Class cls = Loader.loadClass(router).asSubclass(AsyncQueueFullPolicy.class); - LOGGER.debug("Creating custom AsyncQueueFullPolicy '{}'", router); - return cls.newInstance(); - } catch (final Exception ex) { - LOGGER.debug("Using DefaultAsyncQueueFullPolicy. Could not create custom AsyncQueueFullPolicy '{}': {}", router, - ex.toString()); - return new DefaultAsyncQueueFullPolicy(); - } - } - - private static AsyncQueueFullPolicy createDiscardingAsyncQueueFullPolicy() { - final PropertyEnvironment properties = PropertiesUtil.getProperties(); - final String level = properties.getStringProperty(Log4jProperties.ASYNC_LOGGER_DISCARD_THRESHOLD, Level.INFO.name()); - final Level thresholdLevel = Level.toLevel(level, Level.INFO); - LOGGER.debug("Creating custom DiscardingAsyncQueueFullPolicy(discardThreshold:{})", thresholdLevel); - return new DiscardingAsyncQueueFullPolicy(thresholdLevel); + || policy.getSimpleName().equals(propertyValue); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactory.java index 51597b60039..15e3c2dc652 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactory.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.async; +import org.apache.logging.log4j.plugins.di.Key; + import com.lmax.disruptor.WaitStrategy; /** @@ -26,6 +27,8 @@ * @since 2.17.3 */ public interface AsyncWaitStrategyFactory { + Key KEY = new Key<>() {}; + /** * Creates and returns a non-null implementation of the LMAX Disruptor's WaitStrategy interface. * This WaitStrategy will be used by Log4j Async Loggers and Async LoggerConfigs. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfig.java index fb9fdf423ec..875bd04c97c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfig.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfig.java @@ -16,16 +16,20 @@ */ package org.apache.logging.log4j.core.async; +import java.util.Objects; + import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; +import org.apache.logging.log4j.spi.ClassFactory; +import org.apache.logging.log4j.spi.InstanceFactory; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; - -import java.util.Objects; +import org.apache.logging.log4j.util.Cast; /** * This class allows users to configure the factory used to create @@ -42,9 +46,14 @@ public class AsyncWaitStrategyFactoryConfig { protected static final Logger LOGGER = StatusLogger.getLogger(); private final String factoryClassName; + private final ClassFactory classFactory; + private final InstanceFactory instanceFactory; - public AsyncWaitStrategyFactoryConfig(final String factoryClassName) { + public AsyncWaitStrategyFactoryConfig(final String factoryClassName, final ClassFactory classFactory, + final InstanceFactory instanceFactory) { this.factoryClassName = Objects.requireNonNull(factoryClassName, "factoryClassName"); + this.classFactory = classFactory; + this.instanceFactory = instanceFactory; } @PluginFactory @@ -59,45 +68,65 @@ public static > B newBuilder * The type to build */ public static class Builder> - implements org.apache.logging.log4j.core.util.Builder { + implements org.apache.logging.log4j.plugins.util.Builder { + - @PluginBuilderAttribute("class") - @Required(message = "AsyncWaitStrategyFactory cannot be configured without a factory class name") private String factoryClassName; + private ClassFactory classFactory; + private InstanceFactory instanceFactory; public String getFactoryClassName() { return factoryClassName; } - public B withFactoryClassName(String className) { + @Inject + public B setFactoryClassName( + @PluginBuilderAttribute("class") + @Required(message = "AsyncWaitStrategyFactory cannot be configured without a factory class name") + String className) { this.factoryClassName = className; return asBuilder(); } + public ClassFactory getClassFactory() { + if (classFactory == null) { + classFactory = LoggingSystem.getInstance().getClassFactory(); + } + return classFactory; + } + + @Inject + public B setClassFactory(final ClassFactory classFactory) { + this.classFactory = classFactory; + return asBuilder(); + } + + public InstanceFactory getInstanceFactory() { + if (instanceFactory == null) { + return LoggingSystem.getInstance().getInstanceFactory(); + } + return instanceFactory; + } + + @Inject + public B setInstanceFactory(final InstanceFactory instanceFactory) { + this.instanceFactory = instanceFactory; + return asBuilder(); + } + @Override public AsyncWaitStrategyFactoryConfig build() { - return new AsyncWaitStrategyFactoryConfig(factoryClassName); + return new AsyncWaitStrategyFactoryConfig(getFactoryClassName(), getClassFactory(), getInstanceFactory()); } - @SuppressWarnings("unchecked") public B asBuilder() { - return (B) this; + return Cast.cast(this); } } public AsyncWaitStrategyFactory createWaitStrategyFactory() { - try { - @SuppressWarnings("unchecked") - final Class klass = (Class) Loader.loadClass(factoryClassName); - if (AsyncWaitStrategyFactory.class.isAssignableFrom(klass)) { - return klass.newInstance(); - } - LOGGER.error("Ignoring factory '{}': it is not assignable to AsyncWaitStrategyFactory", factoryClassName); - return null; - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - LOGGER.info("Invalid implementation class name value: error creating AsyncWaitStrategyFactory {}: {}", factoryClassName, e); - return null; - } - + return classFactory.tryGetClass(factoryClassName, AsyncWaitStrategyFactory.class) + .flatMap(instanceFactory::tryGetInstance) + .orElse(null); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java index 9658f0302f9..be90f95e2fb 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java @@ -1,44 +1,49 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.async; - -import java.net.URI; - -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.selector.BasicContextSelector; -import org.apache.logging.log4j.plugins.Inject; -import org.apache.logging.log4j.plugins.Singleton; -import org.apache.logging.log4j.plugins.di.Injector; - -/** - * Returns either this Thread's context or the default {@link AsyncLoggerContext}. - * Single-application instances should prefer this implementation over the {@link AsyncLoggerContextSelector} - * due to the reduced overhead avoiding classloader lookups. - */ -@Singleton -public class BasicAsyncLoggerContextSelector extends BasicContextSelector { - - @Inject - public BasicAsyncLoggerContextSelector(Injector injector) { - super(injector); - } - - @Override - protected LoggerContext createContext() { - return new AsyncLoggerContext("AsyncDefault", null, (URI) null, injector); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.async; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.selector.BasicContextSelector; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.plugins.Singleton; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.SimpleScope; +import org.apache.logging.log4j.util.PropertyResolver; + +/** + * Returns either this Thread's context or the default {@link AsyncLoggerContext}. + * Single-application instances should prefer this implementation over the {@link AsyncLoggerContextSelector} + * due to the reduced overhead avoiding classloader lookups. + */ +@Singleton +public class BasicAsyncLoggerContextSelector extends BasicContextSelector { + + @Inject + public BasicAsyncLoggerContextSelector(final Injector injector, final PropertyResolver resolver) { + super(injector, resolver); + } + + @Override + protected LoggerContext createContext() { + final Injector loggerContextInjector = injector.copy(); + loggerContextInjector.registerScope(ContextScoped.class, new SimpleScope("LoggerContext; name=AsyncDefault")); + final AsyncLoggerContext.Builder builder = AsyncLoggerContext.newAsyncBuilder().setName("AsyncDefault"); + loggerContextInjector.injectMembers(builder); + return builder.get(); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DefaultAsyncWaitStrategyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DefaultAsyncWaitStrategyFactory.java index f2e9b5d3af5..1052a0d5cee 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DefaultAsyncWaitStrategyFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DefaultAsyncWaitStrategyFactory.java @@ -19,8 +19,9 @@ import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; import org.apache.logging.log4j.util.Strings; import com.lmax.disruptor.BlockingWaitStrategy; @@ -30,28 +31,29 @@ import com.lmax.disruptor.YieldingWaitStrategy; class DefaultAsyncWaitStrategyFactory implements AsyncWaitStrategyFactory { - static final String DEFAULT_WAIT_STRATEGY_CLASSNAME = TimeoutBlockingWaitStrategy.class.getName(); private static final Logger LOGGER = StatusLogger.getLogger(); + private final PropertyResolver propertyResolver; private final String propertyName; - public DefaultAsyncWaitStrategyFactory(String propertyName) { + public DefaultAsyncWaitStrategyFactory(final PropertyResolver propertyResolver, final String propertyName) { + this.propertyResolver = propertyResolver; this.propertyName = propertyName; } @Override public WaitStrategy createWaitStrategy() { - final String strategy = PropertiesUtil.getProperties().getStringProperty(propertyName, "TIMEOUT"); - LOGGER.trace("DefaultAsyncWaitStrategyFactory property {}={}", propertyName, strategy); - final String strategyUp = Strings.toRootUpperCase(strategy); + final String strategyUp = propertyResolver + .getString(propertyName) + .map(Strings::toRootUpperCase) + .orElse("TIMEOUT"); // String (not enum) is deliberately used here to avoid IllegalArgumentException being thrown. In case of // incorrect property value, default WaitStrategy is created. switch (strategyUp) { case "SLEEP": - final long sleepTimeNs = - parseAdditionalLongProperty(propertyName, "SleepTimeNs", 100L); - final String key = getFullPropertyKey(propertyName, "Retries"); - final int retries = - PropertiesUtil.getProperties().getIntegerProperty(key, 200); + final String sleepTimeKey = getFullPropertyKey(propertyName, "SleepTimeNs"); + final long sleepTimeNs = propertyResolver.getLong(sleepTimeKey).orElse(100L); + final String retriesKey = getFullPropertyKey(propertyName, "Retries"); + final int retries = propertyResolver.getInt(retriesKey).orElse(200); LOGGER.trace("DefaultAsyncWaitStrategyFactory creating SleepingWaitStrategy(retries={}, sleepTimeNs={})", retries, sleepTimeNs); return new SleepingWaitStrategy(retries, sleepTimeNs); case "YIELD": @@ -64,32 +66,25 @@ public WaitStrategy createWaitStrategy() { LOGGER.trace("DefaultAsyncWaitStrategyFactory creating BusySpinWaitStrategy"); return new BusySpinWaitStrategy(); case "TIMEOUT": - return createDefaultWaitStrategy(propertyName); default: return createDefaultWaitStrategy(propertyName); } } static WaitStrategy createDefaultWaitStrategy(final String propertyName) { - final long timeoutMillis = parseAdditionalLongProperty(propertyName, "Timeout", 10L); + final String key = getFullPropertyKey(propertyName, "Timeout"); + final long timeoutMillis = LoggingSystem.getPropertyResolver().getLong(key).orElse(10L); LOGGER.trace("DefaultAsyncWaitStrategyFactory creating TimeoutBlockingWaitStrategy(timeout={}, unit=MILLIS)", timeoutMillis); return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS); } private static String getFullPropertyKey(final String strategyKey, final String additionalKey) { if (strategyKey.startsWith("AsyncLogger.")) { - return "AsyncLogger." + additionalKey; + return "log4j2.*.AsyncLogger." + additionalKey; } else if (strategyKey.startsWith("AsyncLoggerConfig.")) { - return "AsyncLoggerConfig." + additionalKey; + return "log4j2.*.AsyncLoggerConfig." + additionalKey; } return strategyKey + additionalKey; } - private static long parseAdditionalLongProperty( - final String propertyName, - final String additionalKey, - long defaultValue) { - final String key = getFullPropertyKey(propertyName, additionalKey); - return PropertiesUtil.getProperties().getLongProperty(key, defaultValue); - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorConfiguration.java new file mode 100644 index 00000000000..d66b4d24fc7 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorConfiguration.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.async; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.util.Integers; +import org.apache.logging.log4j.core.util.Log4jThread; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.spi.ClassFactory; +import org.apache.logging.log4j.spi.InstanceFactory; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Cast; +import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.PropertyResolver; + +import com.lmax.disruptor.ExceptionHandler; +import com.lmax.disruptor.WaitStrategy; + +import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; + +/** + * Utility methods for getting Disruptor related configuration. + */ +@InternalApi +public class DisruptorConfiguration { + private static final Logger LOGGER = StatusLogger.getLogger(); + private static final int RINGBUFFER_MIN_SIZE = 128; + private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024; + private static final int RINGBUFFER_NO_GC_DEFAULT_SIZE = 4 * 1024; + + private final PropertyResolver propertyResolver; + private final ClassFactory classFactory; + private final InstanceFactory instanceFactory; + + @Inject + DisruptorConfiguration(final PropertyResolver resolver, final ClassFactory classFactory, final InstanceFactory instanceFactory) { + propertyResolver = resolver; + this.classFactory = classFactory; + this.instanceFactory = instanceFactory; + } + + WaitStrategy createWaitStrategy(final String propertyName, final AsyncWaitStrategyFactory asyncWaitStrategyFactory) { + if (asyncWaitStrategyFactory == null) { + LOGGER.debug("No AsyncWaitStrategyFactory was configured in the configuration, using default factory..."); + return new DefaultAsyncWaitStrategyFactory(propertyResolver, propertyName).createWaitStrategy(); + } + LOGGER.debug("Using configured AsyncWaitStrategyFactory {}", asyncWaitStrategyFactory.getClass().getName()); + return asyncWaitStrategyFactory.createWaitStrategy(); + } + + int calculateRingBufferSize(final String propertyName) { + int ringBufferSize = isThreadLocalsEnabled(propertyResolver) ? RINGBUFFER_NO_GC_DEFAULT_SIZE : RINGBUFFER_DEFAULT_SIZE; + int size = propertyResolver.getInt(propertyName).orElse(ringBufferSize); + if (size < RINGBUFFER_MIN_SIZE) { + LOGGER.warn("Invalid RingBufferSize {}, using minimum size {}.", size, RINGBUFFER_MIN_SIZE); + size = RINGBUFFER_MIN_SIZE; + } + ringBufferSize = size; + return Integers.ceilingNextPowerOfTwo(ringBufferSize); + } + + /** + * LOG4J2-2606: Users encountered excessive CPU utilization with Disruptor v3.4.2 when the application + * was logging more than the underlying appender could keep up with and the ringbuffer became full, + * especially when the number of application threads vastly outnumbered the number of cores. + * CPU utilization is significantly reduced by restricting access to the enqueue operation. + */ + boolean synchronizeEnqueueWhenQueueFull(final String propertyName, final long backgroundThreadId) { + return propertyResolver.getBoolean(propertyName, true) + // Background thread must never block + && backgroundThreadId != Thread.currentThread().getId() + // Threads owned by log4j are most likely to result in + // deadlocks because they generally consume events. + // This prevents deadlocks between AsyncLoggerContext + // disruptors. + && !(Thread.currentThread() instanceof Log4jThread); + } + + // TODO(ms): default bindings for LMAX classes should go in a conditionally-loaded bundle class similar to ConditionalOnClass + ExceptionHandler getAsyncLoggerExceptionHandler() { + return propertyResolver.getString(Log4jProperties.ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME) + .flatMap(className -> classFactory.tryGetClass(className, ExceptionHandler.class)) + .>flatMap(type -> Cast.cast(instanceFactory.tryGetInstance(type))) + .orElseGet(AsyncLoggerDefaultExceptionHandler::new); + } + + ExceptionHandler getAsyncLoggerConfigExceptionHandler() { + return propertyResolver.getString(Log4jProperties.ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME) + .flatMap(className -> classFactory.tryGetClass(className, ExceptionHandler.class)) + .>flatMap(type -> Cast.cast(instanceFactory.tryGetInstance(type))) + .orElseGet(AsyncLoggerConfigDefaultExceptionHandler::new); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorUtil.java deleted file mode 100644 index cf61a736834..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorUtil.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.async; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Integers; -import org.apache.logging.log4j.core.util.Loader; -import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; - -import com.lmax.disruptor.ExceptionHandler; -import com.lmax.disruptor.WaitStrategy; - -import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; - -/** - * Utility methods for getting Disruptor related configuration. - */ -final class DisruptorUtil { - private static final Logger LOGGER = StatusLogger.getLogger(); - private static final int RINGBUFFER_MIN_SIZE = 128; - private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024; - private static final int RINGBUFFER_NO_GC_DEFAULT_SIZE = 4 * 1024; - - /** - * LOG4J2-2606: Users encountered excessive CPU utilization with Disruptor v3.4.2 when the application - * was logging more than the underlying appender could keep up with and the ringbuffer became full, - * especially when the number of application threads vastly outnumbered the number of cores. - * CPU utilization is significantly reduced by restricting access to the enqueue operation. - */ - static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties() - .getBooleanProperty(Log4jProperties.ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, true); - static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties() - .getBooleanProperty(Log4jProperties.ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, true); - - private DisruptorUtil() { - } - - static WaitStrategy createWaitStrategy(final String propertyName, - final AsyncWaitStrategyFactory asyncWaitStrategyFactory) { - - if (asyncWaitStrategyFactory == null) { - LOGGER.debug("No AsyncWaitStrategyFactory was configured in the configuration, using default factory..."); - return new DefaultAsyncWaitStrategyFactory(propertyName).createWaitStrategy(); - } - LOGGER.debug("Using configured AsyncWaitStrategyFactory {}", asyncWaitStrategyFactory.getClass().getName()); - return asyncWaitStrategyFactory.createWaitStrategy(); - } - - static int calculateRingBufferSize(final String propertyName) { - int ringBufferSize = isThreadLocalsEnabled() ? RINGBUFFER_NO_GC_DEFAULT_SIZE : RINGBUFFER_DEFAULT_SIZE; - final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName, - String.valueOf(ringBufferSize)); - try { - int size = Integer.parseInt(userPreferredRBSize); - if (size < RINGBUFFER_MIN_SIZE) { - size = RINGBUFFER_MIN_SIZE; - LOGGER.warn("Invalid RingBufferSize {}, using minimum size {}.", userPreferredRBSize, - RINGBUFFER_MIN_SIZE); - } - ringBufferSize = size; - } catch (final Exception ex) { - LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", userPreferredRBSize, ringBufferSize); - } - return Integers.ceilingNextPowerOfTwo(ringBufferSize); - } - - static ExceptionHandler getAsyncLoggerExceptionHandler() { - final String cls = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME); - if (cls == null) { - return new AsyncLoggerDefaultExceptionHandler(); - } - try { - @SuppressWarnings("unchecked") - final Class> klass = - (Class>) Loader.loadClass(cls); - return klass.newInstance(); - } catch (final Exception e) { - LOGGER.debug("Invalid {} value: error creating {}: ", Log4jProperties.ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME, cls, e); - return new AsyncLoggerDefaultExceptionHandler(); - } - } - - static ExceptionHandler getAsyncLoggerConfigExceptionHandler() { - final String cls = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME); - if (cls == null) { - return new AsyncLoggerConfigDefaultExceptionHandler(); - } - try { - @SuppressWarnings("unchecked") - final Class> klass = - (Class>) Loader.loadClass(cls); - return klass.newInstance(); - } catch (final Exception e) { - LOGGER.debug("Invalid {} value: error creating {}: ", Log4jProperties.ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME, cls, e); - return new AsyncLoggerConfigDefaultExceptionHandler(); - } - } - - /** - * Returns the thread ID of the background appender thread. This allows us to detect Logger.log() calls initiated - * from the appender thread, which may cause deadlock when the RingBuffer is full. (LOG4J2-471) - * - * @param executor runs the appender thread - * @return the thread ID of the background appender thread - */ - public static long getExecutorThreadId(final ExecutorService executor) { - final Future result = executor.submit(() -> Thread.currentThread().getId()); - try { - return result.get(); - } catch (final Exception ex) { - final String msg = "Could not obtain executor thread Id. " - + "Giving up to avoid the risk of application deadlock."; - throw new IllegalStateException(msg, ex); - } - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/InternalAsyncUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/InternalAsyncUtil.java index 4959733b706..372b7515c96 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/InternalAsyncUtil.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/InternalAsyncUtil.java @@ -16,9 +16,11 @@ */ package org.apache.logging.log4j.core.async; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.message.AsynchronouslyFormattable; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.spi.LoggingSystem; +import org.apache.logging.log4j.util.InternalApi; /** * Helper class providing some async logging-related functionality. @@ -26,11 +28,12 @@ * Consider this class private. *

    */ +@InternalApi public class InternalAsyncUtil { /** * Returns the specified message, with its content frozen unless system property - * {@code log4j.format.msg.async} is true or the message class is annotated with - * {@link AsynchronouslyFormattable}. + * {@value Log4jProperties#ASYNC_LOGGER_FORMAT_MESSAGES_IN_BACKGROUND} is true or + * the message class is annotated with {@link AsynchronouslyFormattable}. * * @param msg the message object to inspect, modify and return * @return Returns the specified message, with its content frozen @@ -44,7 +47,12 @@ public static Message makeMessageImmutable(final Message msg) { } private static boolean canFormatMessageInBackground(final Message message) { - return Constants.FORMAT_MESSAGES_IN_BACKGROUND // LOG4J2-898: user wants to format all msgs in background + return isBackgroundFormattingEnabled() || message.getClass().isAnnotationPresent(AsynchronouslyFormattable.class); // LOG4J2-1718 } + + private static boolean isBackgroundFormattingEnabled() { + // LOG4J2-898: user wants to format all msgs in background + return LoggingSystem.getPropertyResolver().getBoolean(Log4jProperties.ASYNC_LOGGER_FORMAT_MESSAGES_IN_BACKGROUND, false); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 4d58ae5309f..34db2a835e4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -16,22 +16,23 @@ */ package org.apache.logging.log4j.core.async; -import java.io.IOException; import java.util.Arrays; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.LogEventBuilder; import org.apache.logging.log4j.core.impl.MementoMessage; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.core.time.NanoClock; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterConsumer; import org.apache.logging.log4j.message.ParameterVisitable; @@ -39,12 +40,11 @@ import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.message.TimestampMessage; import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; -import com.lmax.disruptor.EventFactory; - import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; /** @@ -53,23 +53,9 @@ */ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitable { - /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */ - public static final Factory FACTORY = new Factory(); - private static final long serialVersionUID = 8462119088943934758L; private static final Message EMPTY = new SimpleMessage(Strings.EMPTY); - /** - * Creates the events that will be put in the RingBuffer. - */ - private static class Factory implements EventFactory { - - @Override - public RingBufferLogEvent newInstance() { - return new RingBufferLogEvent(); - } - } - private boolean populated; private int threadPriority; private long threadId; @@ -87,19 +73,23 @@ public RingBufferLogEvent newInstance() { private Object[] parameters; private transient Throwable thrown; private ThrowableProxy thrownProxy; - private StringMap contextData = ContextDataFactory.createContextData(); + private StringMap contextData; private Marker marker; private String fqcn; private StackTraceElement location; private ContextStack contextStack; private transient AsyncLogger asyncLogger; + private transient ContextDataInjector contextDataInjector; + private transient ContextDataFactory contextDataFactory; + public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker, final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable, final StringMap mutableContextData, final ContextStack aContextStack, final long threadId, final String threadName, final int threadPriority, final StackTraceElement aLocation, - final Clock clock, final NanoClock nanoClock) { + final Clock clock, final NanoClock nanoClock, final ContextDataFactory factory, + final ContextDataInjector injector) { this.threadPriority = threadPriority; this.threadId = threadId; this.level = aLevel; @@ -116,6 +106,8 @@ public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, this.contextData = mutableContextData; this.contextStack = aContextStack; this.asyncLogger = anAsyncLogger; + this.contextDataFactory = factory; + this.contextDataInjector = injector; this.populated = true; } @@ -148,7 +140,7 @@ private StringBuilder getMessageTextForWriting() { if (messageText == null) { // Happens the first time messageText is requested or if a user logs // a custom reused message when Constants.ENABLE_THREADLOCALS is false - messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE); + messageText = new StringBuilder(GarbageFreeConfiguration.getDefaultConfiguration().getInitialReusableMessageSize()); } messageText.setLength(0); return messageText; @@ -346,9 +338,13 @@ public ThrowableProxy getThrownProxy() { return this.thrownProxy; } - @SuppressWarnings("unchecked") @Override public ReadOnlyStringMap getContextData() { + if (contextData == null) { + contextData = contextDataFactory != null + ? contextDataFactory.createContextData() + : new SortedArrayStringMap(); + } return contextData; } @@ -423,7 +419,7 @@ public void clear() { // ensure that excessively long char[] arrays are not kept in memory forever if (isThreadLocalsEnabled()) { - StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE); + StringBuilders.trimToMaxSize(messageText, GarbageFreeConfiguration.getDefaultConfiguration().getMaxReusableMessageSize()); if (parameters != null) { Arrays.fill(parameters, null); @@ -437,44 +433,36 @@ public void clear() { } } - private void writeObject(final java.io.ObjectOutputStream out) throws IOException { - getThrownProxy(); // initialize the ThrowableProxy before serializing - out.defaultWriteObject(); - } - /** * Creates and returns a new immutable copy of this {@code RingBufferLogEvent}. * * @return a new immutable copy of the data in this {@code RingBufferLogEvent} */ public LogEvent createMemento() { - return new Log4jLogEvent.Builder(this).build(); - + return LogEvent.builderFrom(this).toImmutable(); } - /** - * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}. - * @param builder the builder whose fields to populate - */ - public void initializeBuilder(final Log4jLogEvent.Builder builder) { - builder.setContextData(contextData) // - .setContextStack(contextStack) // - .setEndOfBatch(endOfBatch) // - .setIncludeLocation(includeLocation) // + public void initializeBuilder(final LogEventBuilder builder) { + builder + .setContextDataFactory(contextDataFactory) + .setContextDataInjector(contextDataInjector) + .setContextData(contextData) + .setContextStack(contextStack) + .endOfBatch(endOfBatch) + .includeLocation(includeLocation) .setLevel(getLevel()) // ensure non-null - .setLoggerFqcn(fqcn) // - .setLoggerName(loggerName) // - .setMarker(marker) // + .setLoggerFqcn(fqcn) + .setLoggerName(loggerName) + .setMarker(marker) .setMessage(memento()) // ensure non-null & immutable - .setNanoTime(nanoTime) // - .setSource(location) // - .setThreadId(threadId) // - .setThreadName(threadName) // - .setThreadPriority(threadPriority) // + .setNanoTime(nanoTime) + .setSource(location) + .setThreadId(threadId) + .setThreadName(threadName) + .setThreadPriority(threadPriority) .setThrown(getThrown()) // may deserialize from thrownProxy .setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy - .setInstant(instant) // - ; + .setInstant(instant); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java index 33b72929bb8..9264a8707f6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java @@ -16,16 +16,19 @@ */ package org.apache.logging.log4j.core.async; -import com.lmax.disruptor.EventTranslator; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringMap; +import com.lmax.disruptor.EventTranslator; + /** * This class is responsible for writing elements that make up a log event into * the ringbuffer {@code RingBufferLogEvent}. After this translator populated @@ -36,6 +39,7 @@ public class RingBufferLogEventTranslator implements EventTranslator { private ContextDataInjector contextDataInjector; + private ContextDataFactory contextDataFactory; private AsyncLogger asyncLogger; String loggerName; protected Marker marker; @@ -55,11 +59,13 @@ public class RingBufferLogEventTranslator implements @Override public void translateTo(final RingBufferLogEvent event, final long sequence) { try { - event.setValues(asyncLogger, loggerName, marker, fqcn, level, message, thrown, - // config properties are taken care of in the EventHandler thread - // in the AsyncLogger#actualAsyncLog method - contextDataInjector.injectContextData(null, (StringMap) event.getContextData()), contextStack, - threadId, threadName, threadPriority, location, clock, nanoClock); + final ReadOnlyStringMap contextData = event.getContextData(); + final StringMap reusable = contextData != null ? (StringMap) contextData : contextDataFactory.createContextData(); + // config properties are taken care of in the EventHandler thread + // in the AsyncLogger#actualAsyncLog method + final StringMap mutableContextData = contextDataInjector.injectContextData(null, reusable); + event.setValues(asyncLogger, loggerName, marker, fqcn, level, message, thrown, mutableContextData, contextStack, + threadId, threadName, threadPriority, location, clock, nanoClock, contextDataFactory, contextDataInjector); } finally { clear(); // clear the translator } @@ -80,14 +86,15 @@ void clear() { null, // location null, // clock null, // nanoClock - null // contextDataInjector - ); + null, // contextDataInjector + null); // contextDataFactory } public void setBasicValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker, final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable, final ContextStack aContextStack, final StackTraceElement aLocation, - final Clock aClock, final NanoClock aNanoClock, final ContextDataInjector aContextDataInjector) { + final Clock aClock, final NanoClock aNanoClock, final ContextDataInjector aContextDataInjector, + final ContextDataFactory aContextDataFactory) { this.asyncLogger = anAsyncLogger; this.loggerName = aLoggerName; this.marker = aMarker; @@ -100,6 +107,7 @@ public void setBasicValues(final AsyncLogger anAsyncLogger, final String aLogger this.clock = aClock; this.nanoClock = aNanoClock; this.contextDataInjector = aContextDataInjector; + this.contextDataFactory = aContextDataFactory; } public void updateThreadValues() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java index 636857f4f35..de64af0c917 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java @@ -16,14 +16,6 @@ */ package org.apache.logging.log4j.core.async; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.Constants; -import org.apache.logging.log4j.util.PropertiesUtil; - /** * Strategy for deciding whether thread name should be cached or not. */ @@ -46,41 +38,8 @@ public String getThreadName() { } }; - private static final StatusLogger LOGGER = StatusLogger.getLogger(); private static final ThreadLocal THREADLOCAL_NAME = new ThreadLocal<>(); - static final ThreadNameCachingStrategy DEFAULT_STRATEGY = isAllocatingThreadGetName() ? CACHED : UNCACHED; abstract String getThreadName(); - public static ThreadNameCachingStrategy create() { - final String name = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY); - try { - final ThreadNameCachingStrategy result = name != null ? ThreadNameCachingStrategy.valueOf(name) : DEFAULT_STRATEGY; - LOGGER.debug("{}={} (user specified {}, default is {})", Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, - result.name(), name, DEFAULT_STRATEGY.name()); - return result; - } catch (final Exception ex) { - LOGGER.debug("Using {}.{}: '{}' not valid: {}", Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, - DEFAULT_STRATEGY.name(), name, ex.toString()); - return DEFAULT_STRATEGY; - } - } - - static boolean isAllocatingThreadGetName() { - // LOG4J2-2052, LOG4J2-2635 JDK 8u102 ("1.8.0_102") removed the String allocation in Thread.getName() - if (Constants.JAVA_MAJOR_VERSION == 8) { - try { - final Pattern javaVersionPattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)_(\\d+)"); - final Matcher m = javaVersionPattern.matcher(System.getProperty("java.version")); - if (m.matches()) { - return Integer.parseInt(m.group(3)) == 0 && Integer.parseInt(m.group(4)) < 102; - } - return true; - } catch (final Exception e) { - return true; - } - } else { - return Constants.JAVA_MAJOR_VERSION < 8; - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategyFactory.java new file mode 100644 index 00000000000..84e1df81602 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategyFactory.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.async; + +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.util.PropertyResolver; + +@ContextScoped +public class ThreadNameCachingStrategyFactory implements Supplier { + private static final StatusLogger LOGGER = StatusLogger.getLogger(); + static final ThreadNameCachingStrategy DEFAULT_STRATEGY = + isAllocatingThreadGetName() ? ThreadNameCachingStrategy.CACHED : ThreadNameCachingStrategy.UNCACHED; + private final PropertyResolver propertyResolver; + + @Inject + public ThreadNameCachingStrategyFactory(final PropertyResolver resolver) { + propertyResolver = resolver; + } + + @Override + public ThreadNameCachingStrategy get() { + return propertyResolver + .getString(Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY) + .map(name -> { + try { + final ThreadNameCachingStrategy result = ThreadNameCachingStrategy.valueOf(name); + LOGGER.debug("{}={} (user specified {}, default is {})", + Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, result.name(), name, + DEFAULT_STRATEGY.name()); + return result; + } catch (final Exception e) { + LOGGER.debug("Using {}.{}: '{}' not valid", + Log4jProperties.ASYNC_LOGGER_THREAD_NAME_STRATEGY, DEFAULT_STRATEGY.name(), name, e); + return DEFAULT_STRATEGY; + } + }) + .orElse(DEFAULT_STRATEGY); + } + + static boolean isAllocatingThreadGetName() { + // LOG4J2-2052, LOG4J2-2635 JDK 8u102 ("1.8.0_102") removed the String allocation in Thread.getName() + if (Constants.JAVA_MAJOR_VERSION == 8) { + try { + final Pattern javaVersionPattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)_(\\d+)"); + final Matcher m = javaVersionPattern.matcher(System.getProperty("java.version")); + if (m.matches()) { + return Integer.parseInt(m.group(3)) == 0 && Integer.parseInt(m.group(4)) < 102; + } + return true; + } catch (final Exception e) { + return true; + } + } else { + return Constants.JAVA_MAJOR_VERSION < 8; + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java index db1a5c83250..3b469d302a8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.core.config; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; import java.lang.invoke.MethodHandles; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -28,19 +25,20 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import java.util.function.Supplier; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Core; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.Version; @@ -67,23 +65,22 @@ import org.apache.logging.log4j.core.script.ScriptManager; import org.apache.logging.log4j.core.script.ScriptManagerFactory; import org.apache.logging.log4j.core.time.NanoClock; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.Source; import org.apache.logging.log4j.core.util.WatchManager; import org.apache.logging.log4j.core.util.Watcher; import org.apache.logging.log4j.core.util.WatcherFactory; +import org.apache.logging.log4j.plugins.ConfigurationScoped; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Node; -import org.apache.logging.log4j.plugins.di.DI; import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.plugins.di.Keys; +import org.apache.logging.log4j.plugins.di.SimpleScope; import org.apache.logging.log4j.plugins.model.PluginNamespace; import org.apache.logging.log4j.plugins.model.PluginType; import org.apache.logging.log4j.util.Cast; -import org.apache.logging.log4j.util.Lazy; import org.apache.logging.log4j.util.NameUtil; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; import org.apache.logging.log4j.util.ServiceRegistry; /** @@ -101,11 +98,6 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement */ protected final List listeners = new CopyOnWriteArrayList<>(); - /** - * Packages found in configuration "packages" attribute. - */ - protected final List pluginPackages = new ArrayList<>(); - /** * Core plugins. */ @@ -127,6 +119,8 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement protected ScriptManager scriptManager; protected final Injector injector; + protected final PropertyResolver propertyResolver; + /** * The Advertiser which exposes appender configurations to external systems. */ @@ -142,7 +136,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement private final Interpolator tempLookup; private final StrSubstitutor runtimeStrSubstitutor; private final StrSubstitutor configurationStrSubstitutor; - private LoggerConfig root = new LoggerConfig(); + private LoggerConfig root; private final ConcurrentMap componentMap = new ConcurrentHashMap<>(); private final ConfigurationSource configurationSource; private final ConfigurationScheduler configurationScheduler; @@ -155,17 +149,11 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement * Constructor. */ protected AbstractConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) { - this.loggerContext = new WeakReference<>(loggerContext); - // The loggerContext is null for the NullConfiguration class. - // this.loggerContext = new WeakReference(Objects.requireNonNull(loggerContext, "loggerContext is null")); + this.loggerContext = new WeakReference<>(Objects.requireNonNull(loggerContext, "loggerContext is null")); this.configurationSource = Objects.requireNonNull(configurationSource, "configurationSource is null"); - if (loggerContext != null) { - injector = loggerContext.getInjector(); - } else { - // for NullConfiguration - injector = DI.createInjector(); - injector.init(); - } + injector = loggerContext.getInjector().copy(); + injector.registerScope(ConfigurationScoped.class, new SimpleScope(() -> "ConfigurationScoped; name=" + getName())); + propertyResolver = loggerContext.getPropertyResolver(); componentMap.put(Configuration.CONTEXT_PROPERTIES, properties); interpolatorFactory = injector.getInstance(InterpolatorFactory.class); tempLookup = interpolatorFactory.newInterpolator(new PropertiesLookup(properties)); @@ -174,6 +162,10 @@ protected AbstractConfiguration(final LoggerContext loggerContext, final Configu configurationStrSubstitutor = new ConfigurationStrSubstitutor(runtimeStrSubstitutor); configurationScheduler = injector.getInstance(ConfigurationScheduler.class); watchManager = injector.getInstance(WatchManager.class); + root = LoggerConfig.RootLogger.newRootBuilder() + .setPropertyResolver(propertyResolver) + .setConfig(this) + .get(); setState(State.INITIALIZING); } @@ -183,13 +175,13 @@ public ConfigurationSource getConfigurationSource() { } @Override - public List getPluginPackages() { - return pluginPackages; + public Map getProperties() { + return properties; } @Override - public Map getProperties() { - return properties; + public PropertyResolver getPropertyResolver() { + return propertyResolver; } @Override @@ -230,7 +222,7 @@ public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() { // lazily instantiate only when requested by AsyncLoggers: // loading AsyncLoggerConfigDisruptor requires LMAX Disruptor jar on classpath if (asyncLoggerConfigDisruptor == null) { - asyncLoggerConfigDisruptor = new AsyncLoggerConfigDisruptor(asyncWaitStrategyFactory); + asyncLoggerConfigDisruptor = injector.getInstance(AsyncLoggerConfigDisruptor.class); } return asyncLoggerConfigDisruptor; } @@ -246,9 +238,8 @@ public AsyncWaitStrategyFactory getAsyncWaitStrategyFactory() { @Override public void initialize() { LOGGER.debug("{} initializing configuration {}", Version.getProductString(), this); - injector.registerBinding(Configuration.KEY, () -> this); - runtimeStrSubstitutor.setConfiguration(this); - configurationStrSubstitutor.setConfiguration(this); + injector.injectMembers(runtimeStrSubstitutor); + injector.injectMembers(configurationStrSubstitutor); initializeScriptManager(); corePlugins = injector.getInstance(Core.PLUGIN_NAMESPACE_KEY); final PluginNamespace levelPlugins = injector.getInstance(new @Namespace(Level.CATEGORY) Key<>() {}); @@ -307,10 +298,7 @@ protected void initializeWatchers(final Reconfigurable reconfigurable, final Con private void monitorSource(final Reconfigurable reconfigurable, final ConfigurationSource configSource) { if (configSource.getLastModified() > 0) { final Source cfgSource = new Source(configSource); - final Key key = Key.forClass(WatcherFactory.class); - injector.registerBindingIfAbsent(key, Lazy.lazy(() -> - new WatcherFactory(injector.getInstance(Watcher.PLUGIN_CATEGORY_KEY)))); - final Watcher watcher = injector.getInstance(key) + final Watcher watcher = getInstance(WatcherFactory.class) .newWatcher(cfgSource, this, reconfigurable, listeners, configSource.getLastModified()); if (watcher != null) { watchManager.watch(cfgSource, watcher); @@ -335,7 +323,7 @@ public void start() { watchManager.start(); } if (hasAsyncLoggers()) { - asyncLoggerConfigDisruptor.start(); + ((LifeCycle) getAsyncLoggerConfigDelegate()).start(); } final Set alreadyStarted = new HashSet<>(); for (final LoggerConfig logger : loggerConfigs.values()) { @@ -488,7 +476,7 @@ public void setup() { } protected Level getDefaultStatus() { - return injector.getInstance(Constants.DEFAULT_STATUS_LEVEL_KEY); + return getInstance(Keys.DEFAULT_STATUS_LEVEL_KEY); } protected void createAdvertiser(final String advertiserString, final ConfigurationSource configSource, @@ -511,20 +499,30 @@ private void setupAdvertisement() { final String nodeName = advertiserNode.getName(); final PluginType type = corePlugins.get(nodeName); if (type != null) { - advertiser = injector.getInstance(type.getPluginClass().asSubclass(Advertiser.class)); + advertiser = getInstance(type.getPluginClass().asSubclass(Advertiser.class)); advertisement = advertiser.advertise(advertiserNode.getAttributes()); } } } @Override - public T getComponent(final String componentName) { - return Cast.cast(componentMap.get(componentName)); + public T getInstance(final Class type) { + return injector.getInstance(type); + } + + @Override + public Optional tryGetInstance(final Class type) { + return injector.tryGetInstance(type); } @Override - public Supplier getFactory(final Key key) { - return injector.getFactory(key); + public T getInstance(final Key key) { + return injector.getInstance(key); + } + + @Override + public T getComponent(final String componentName) { + return Cast.cast(componentMap.get(componentName)); } @Override @@ -642,7 +640,6 @@ protected List processSelect(final Node selectNode, final PluginType ty protected void doConfigure() { injector.registerBinding(Keys.SUBSTITUTOR_KEY, () -> configurationStrSubstitutor::replace); - injector.registerBinding(LoggerContext.KEY, () -> loggerContext); processConditionals(rootNode); preConfigure(rootNode); configurationScheduler.start(); @@ -652,7 +649,7 @@ protected void doConfigure() { if (first.getObject() != null) { StrLookup lookup = first.getObject(); if (lookup instanceof LoggerContextAware) { - ((LoggerContextAware) lookup).setLoggerContext(loggerContext.get()); + ((LoggerContextAware) lookup).setLoggerContext(getLoggerContext()); } runtimeStrSubstitutor.setVariableResolver(lookup); configurationStrSubstitutor.setVariableResolver(lookup); @@ -661,7 +658,7 @@ protected void doConfigure() { final Map map = this.getComponent(CONTEXT_PROPERTIES); final StrLookup lookup = map == null ? null : new PropertiesLookup(map); Interpolator interpolator = interpolatorFactory.newInterpolator(lookup); - interpolator.setLoggerContext(loggerContext.get()); + interpolator.setLoggerContext(getLoggerContext()); runtimeStrSubstitutor.setVariableResolver(interpolator); configurationStrSubstitutor.setVariableResolver(interpolator); } @@ -742,7 +739,7 @@ protected void doConfigure() { protected void setToDefault() { // LOG4J2-1176 facilitate memory leak investigation setName(DefaultConfiguration.DEFAULT_NAME + "@" + Integer.toHexString(hashCode())); - final Layout layout = PatternLayout.newBuilder() + final Layout layout = PatternLayout.newBuilder() .setPattern(DefaultConfiguration.DEFAULT_PATTERN) .setConfiguration(this) .build(); @@ -753,10 +750,11 @@ protected void setToDefault() { rootLoggerConfig.addAppender(appender, null, null); final Level defaultLevel = Level.ERROR; - final String levelName = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.CONFIG_DEFAULT_LEVEL, - defaultLevel.name()); - final Level level = Level.valueOf(levelName); - rootLoggerConfig.setLevel(level != null ? level : defaultLevel); + final Level level = propertyResolver + .getString(Log4jProperties.CONFIG_DEFAULT_LEVEL) + .map(Level::valueOf) + .orElse(defaultLevel); + rootLoggerConfig.setLevel(level); } /** @@ -851,17 +849,6 @@ public Advertiser getAdvertiser() { return advertiser; } - /* - * (non-Javadoc) - * - * @see org.apache.logging.log4j.core.config.ReliabilityStrategyFactory#getReliabilityStrategy(org.apache.logging.log4j - * .core.config.LoggerConfig) - */ - @Override - public ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) { - return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig); - } - /** * Associates an Appender with a LoggerConfig. This method is synchronized in case a Logger with the same name is * being updated at the same time. @@ -883,7 +870,12 @@ public synchronized void addLoggerAppender(final org.apache.logging.log4j.core.L if (lc.getName().equals(loggerName)) { lc.addAppender(appender, null, null); } else { - final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive()); + final LoggerConfig nlc = LoggerConfig.newBuilder() + .setLoggerName(loggerName) + .setLevel(lc.getLevel()) + .setAdditivity(lc.isAdditive()) + .setConfig(this) + .get(); nlc.addAppender(appender, null, null); nlc.setParent(lc); loggerConfigs.putIfAbsent(loggerName, nlc); @@ -908,7 +900,12 @@ public synchronized void addLoggerFilter(final org.apache.logging.log4j.core.Log if (lc.getName().equals(loggerName)) { lc.addFilter(filter); } else { - final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive()); + final LoggerConfig nlc = LoggerConfig.newBuilder() + .setLoggerName(loggerName) + .setLevel(lc.getLevel()) + .setAdditivity(lc.isAdditive()) + .setConfig(this) + .get(); nlc.addFilter(filter); nlc.setParent(lc); loggerConfigs.putIfAbsent(loggerName, nlc); @@ -933,7 +930,12 @@ public synchronized void setLoggerAdditive(final org.apache.logging.log4j.core.L if (lc.getName().equals(loggerName)) { lc.setAdditive(additive); } else { - final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), additive); + final LoggerConfig nlc = LoggerConfig.newBuilder() + .setLoggerName(loggerName) + .setLevel(lc.getLevel()) + .setAdditivity(additive) + .setConfig(this) + .get(); nlc.setParent(lc); loggerConfigs.putIfAbsent(loggerName, nlc); setParents(); @@ -1059,6 +1061,7 @@ public void createConfiguration(final Node node, final LogEvent event) { } else { stringSubstitutionStrategy = str -> runtimeStrSubstitutor.replace(event, str); } + // TODO(ms): try removing copy() call here final Injector injector = this.injector.copy().registerBinding(Keys.SUBSTITUTOR_KEY, () -> stringSubstitutionStrategy); injector.configure(node); } @@ -1070,6 +1073,7 @@ public void createConfiguration(final Node node, final LogEvent event) { */ public Object createPluginObject(final Node node) { if (this.getState().equals(State.INITIALIZING)) { + // TODO(ms): try removing copy() call here final Injector injector = this.injector.copy().registerBinding(Keys.SUBSTITUTOR_KEY, () -> configurationStrSubstitutor::replace); return injector.configure(node); @@ -1078,18 +1082,6 @@ public Object createPluginObject(final Node node) { return null; } - /** - * This method is used by Arbiters to create specific children. - * @param type The PluginType. - * @param node The Node. - * @return The created object or null; - * @deprecated use {@link #createPluginObject(Node)} - */ - @Deprecated - public Object createPluginObject(final PluginType type, final Node node) { - return createPluginObject(node); - } - private void setParents() { for (final Map.Entry entry : loggerConfigs.entrySet()) { final LoggerConfig logger = entry.getValue(); @@ -1110,23 +1102,9 @@ private void setParents() { } } - /** - * Reads an InputStream using buffered reads into a byte array buffer. The given InputStream will remain open after - * invocation of this method. - * - * @param is the InputStream to read into a byte array buffer. - * @return a byte array of the InputStream contents. - * @throws IOException if the {@code read} method of the provided InputStream throws this exception. - * @deprecated use {@link InputStream#readAllBytes()} - */ - @Deprecated(since = "3.0.0") - protected static byte[] toByteArray(final InputStream is) throws IOException { - return is.readAllBytes(); - } - @Override public NanoClock getNanoClock() { - return injector.getInstance(NanoClock.class); + return getInstance(NanoClock.class); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java index abc5f59370b..eec9273c470 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java @@ -24,7 +24,6 @@ import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Supplier; /** @@ -33,16 +32,14 @@ public class AwaitUnconditionallyReliabilityStrategy implements ReliabilityStrategy { private static final long DEFAULT_SLEEP_MILLIS = 5000; // 5 seconds - private static final long SLEEP_MILLIS = sleepMillis(); private final LoggerConfig loggerConfig; + private final long sleepMillis; public AwaitUnconditionallyReliabilityStrategy(final LoggerConfig loggerConfig) { this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig is null"); - } - - private static long sleepMillis() { - return PropertiesUtil.getProperties().getLongProperty(Log4jProperties.CONFIG_RELIABILITY_STRATEGY_AWAIT_UNCONDITIONALLY_MILLIS, - DEFAULT_SLEEP_MILLIS); + this.sleepMillis = loggerConfig.getPropertyResolver() + .getLong(Log4jProperties.CONFIG_RELIABILITY_STRATEGY_AWAIT_UNCONDITIONALLY_MILLIS) + .orElse(DEFAULT_SLEEP_MILLIS); } /* @@ -127,7 +124,7 @@ public void beforeStopConfiguration(final Configuration configuration) { // only sleep once per configuration stop if (loggerConfig == configuration.getRootLogger()) { try { - Thread.sleep(SLEEP_MILLIS); + Thread.sleep(sleepMillis); } catch (final InterruptedException e) { StatusLogger.getLogger().warn("Sleep before stop configuration was interrupted."); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java index 53fa9a4f94f..77bcb70f81f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.config; +import java.util.List; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; @@ -33,10 +36,8 @@ import org.apache.logging.log4j.core.util.WatchManager; import org.apache.logging.log4j.plugins.Node; import org.apache.logging.log4j.plugins.di.Key; - -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; +import org.apache.logging.log4j.spi.InstanceFactory; +import org.apache.logging.log4j.util.PropertyResolver; /** * Interface that must be implemented to create a configuration. @@ -46,7 +47,7 @@ * * @see AbstractConfiguration */ -public interface Configuration extends Filterable { +public interface Configuration extends Filterable, InstanceFactory { /** Injection key for the current Configuration. */ Key KEY = new Key<>() {}; @@ -100,16 +101,10 @@ public interface Configuration extends Filterable { void removeLogger(final String name); - /** - * Returns the list of packages to scan for plugins for this Configuration. - * - * @return the list of plugin packages. - * @since 2.1 - */ - List getPluginPackages(); - Map getProperties(); + PropertyResolver getPropertyResolver(); + /** * Returns the root Logger. * @@ -133,13 +128,9 @@ default StrSubstitutor getConfigurationStrSubstitutor() { void createConfiguration(Node node, LogEvent event); - T getComponent(String name); - - Supplier getFactory(Key key); + T getInstance(Key key); - default T getComponent(Key key) { - return getFactory(key).get(); - } + T getComponent(String name); void addComponent(String name, Object object); @@ -208,16 +199,6 @@ default T getComponent(Key key) { */ WatchManager getWatchManager(); - /* - * (non-Javadoc) - * - * @see - * org.apache.logging.log4j.core.config.ReliabilityStrategyFactory#getReliabilityStrategy(org.apache.logging.log4j - * .core.config.LoggerConfig) - */ - - ReliabilityStrategy getReliabilityStrategy(LoggerConfig loggerConfig); - /** * Returns the {@link NanoClock} instance for this configuration. * @@ -233,7 +214,7 @@ default T getComponent(Key key) { void setNanoClock(NanoClock nanoClock); /** - * Gets the logger context. + * Gets the logger context. This may be {@code null} if the context was already garbage-collected. * * @return the logger context. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java index 689e685550e..705c850f5ac 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java @@ -22,9 +22,6 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.lookup.StrSubstitutor; -import org.apache.logging.log4j.core.util.AuthorizationProvider; -import org.apache.logging.log4j.core.util.BasicAuthorizationProvider; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.di.Injector; @@ -32,7 +29,7 @@ import org.apache.logging.log4j.plugins.model.PluginNamespace; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; /** * Factory class for parsed {@link Configuration} objects from a configuration file. @@ -71,7 +68,7 @@ public ConfigurationFactory() { */ public static final String CONFIGURATION_FILE_PROPERTY = Log4jProperties.CONFIG_LOCATION; - public static final String LOG4J1_CONFIGURATION_FILE_PROPERTY = Log4jProperties.CONFIG_V1_FILE_NAME; + public static final String LOG4J1_CONFIGURATION_FILE_PROPERTY = Log4jProperties.CONFIG_V1_LOCATION; public static final String LOG4J1_EXPERIMENTAL = Log4jProperties.CONFIG_V1_COMPATIBILITY_ENABLED; @@ -85,8 +82,6 @@ public ConfigurationFactory() { public static final Key KEY = new Key<>() {}; - public static final Key PLUGIN_CATEGORY_KEY = new @Namespace(NAMESPACE) Key<>() {}; - /** * Allows subclasses access to the status logger without creating another instance. */ @@ -115,39 +110,17 @@ public ConfigurationFactory() { */ private static final String CLASS_PATH_SCHEME = "classpath"; - private static final String[] PREFIXES = {"log4j2.", "log4j2.Configuration."}; - - @Deprecated(since = "3.0.0", forRemoval = true) - public static ConfigurationFactory getInstance() { - return LoggerContext.getContext(false).getInjector().getInstance(KEY); - } + protected PropertyResolver propertyResolver; + protected ConfigurationResolver configurationResolver; - public static AuthorizationProvider authorizationProvider(final PropertyEnvironment props) { - final String authClass = props.getStringProperty(PREFIXES, "authorizationProvider", null); - AuthorizationProvider provider = null; - if (authClass != null) { - try { - final Object obj = LoaderUtil.newInstanceOf(authClass); - if (obj instanceof AuthorizationProvider) { - provider = (AuthorizationProvider) obj; - } else { - LOGGER.warn("{} is not an AuthorizationProvider, using default", obj.getClass().getName()); - } - } catch (final Exception ex) { - LOGGER.warn("Unable to create {}, using default: {}", authClass, ex.getMessage()); - } - } - if (provider == null) { - provider = new BasicAuthorizationProvider(props); - } - return provider; + @Inject + public void setPropertyResolver(final PropertyResolver resolver) { + propertyResolver = resolver; } - protected StrSubstitutor substitutor; - @Inject - public void setSubstitutor(final StrSubstitutor substitutor) { - this.substitutor = substitutor; + public void setConfigurationResolver(final ConfigurationResolver configurationResolver) { + this.configurationResolver = configurationResolver; } protected abstract String[] getSupportedTypes(); @@ -182,10 +155,9 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final S return null; } if (configLocation != null) { - final ConfigurationSource source = ConfigurationSource.fromUri(configLocation); - if (source != null) { - return getConfiguration(loggerContext, source); - } + return configurationResolver.tryResolve(configLocation) + .map(source -> getConfiguration(loggerContext, source)) + .orElse(null); } return null; } @@ -209,12 +181,11 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final S } if (isClassLoaderUri(configLocation)) { final String path = extractClassLoaderUriPath(configLocation); - final ConfigurationSource source = ConfigurationSource.fromResource(path, loader); - if (source != null) { - final Configuration configuration = getConfiguration(loggerContext, source); - if (configuration != null) { - return configuration; - } + final Configuration configuration = configurationResolver.tryResolve(path, loader) + .map(source -> getConfiguration(loggerContext, source)) + .orElse(null); + if (configuration != null) { + return configuration; } } return getConfiguration(loggerContext, name, configLocation); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationProvider.java new file mode 100644 index 00000000000..405ba61ec5d --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationProvider.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.apache.logging.log4j.core.util.NetUtils; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.plugins.Namespace; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.LoaderUtil; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.Strings; + +/** + * Provides configuration instances for configuration sources using an appropriate {@link ConfigurationFactory} plugin. + * Useful as a basis for a dynamic implementation of ConfigurationFactory. + * + * @since 3.0.0 + */ +@ContextScoped +public class ConfigurationProvider { + private static final String ALL_TYPES = "*"; + private static final String OVERRIDE_PARAM = "override"; + private static final Logger LOGGER = StatusLogger.getLogger(); + + private final List factories; + private final ConfigurationResolver configurationResolver; + private final PropertyResolver propertyResolver; + private final StrSubstitutor substitutor; + private final LoggerContext loggerContext; + + @Inject + public ConfigurationProvider(@Namespace(ConfigurationFactory.NAMESPACE) final List factories, + final ConfigurationResolver configurationResolver, + final PropertyResolver propertyResolver, + final StrSubstitutor substitutor, + final LoggerContext context) { + this.factories = factories; + this.configurationResolver = configurationResolver; + this.propertyResolver = propertyResolver; + this.substitutor = substitutor; + loggerContext = context; + } + + public Configuration getConfiguration(final String name, final URI configLocation) { + if (configLocation == null) { + final String configLocationStr = propertyResolver.getString(Log4jProperties.CONFIG_LOCATION) + .map(substitutor::replace) + .orElse(null); + if (configLocationStr != null) { + final String[] sources = parseConfigLocations(configLocationStr); + if (sources.length > 1) { + final List configs = new ArrayList<>(); + for (final String sourceLocation : sources) { + final Configuration config = getConfiguration(null, sourceLocation.trim()); + if (config != null) { + if (config instanceof AbstractConfiguration) { + configs.add((AbstractConfiguration) config); + } else { + LOGGER.error("Failed to created configuration at {}", sourceLocation); + return null; + } + } else { + LOGGER.warn("Unable to create configuration for {}, ignoring", sourceLocation); + } + } + if (configs.size() > 1) { + return new CompositeConfiguration(configs); + } else if (configs.size() == 1) { + return configs.get(0); + } + } + } else { + final String log4j1ConfigStr = propertyResolver.getString(Log4jProperties.CONFIG_V1_LOCATION) + .map(substitutor::replace) + .orElse(null); + if (log4j1ConfigStr != null) { + System.setProperty(Log4jProperties.CONFIG_V1_COMPATIBILITY_ENABLED, "true"); + return getConfiguration(ConfigurationFactory.LOG4J1_VERSION, log4j1ConfigStr); + } + } + + for (final ConfigurationFactory factory : factories) { + final String[] types = factory.getSupportedTypes(); + if (types != null) { + for (final String type : types) { + if (type.equals(ALL_TYPES) || configLocationStr != null && configLocationStr.endsWith(type)) { + final Configuration config = factory.getConfiguration(loggerContext, name, null); + if (config != null) { + return config; + } + } + } + } + } + } else { + // configLocation != null + final String[] sources = parseConfigLocations(configLocation); + if (sources.length > 1) { + final List configs = new ArrayList<>(); + for (final String sourceLocation : sources) { + final Configuration config = getConfiguration(null, sourceLocation.trim()); + if (config instanceof AbstractConfiguration) { + configs.add((AbstractConfiguration) config); + } else { + LOGGER.error("Failed to created configuration at {}", sourceLocation); + return null; + } + } + return new CompositeConfiguration(configs); + } + final String configLocationStr = configLocation.toString(); + for (final ConfigurationFactory factory : factories) { + final String[] types = factory.getSupportedTypes(); + if (types != null) { + for (final String type : types) { + if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) { + final Configuration config = factory.getConfiguration(loggerContext, name, configLocation); + if (config != null) { + return config; + } + } + } + } + } + } + + Configuration config = getConfiguration(true, name); + if (config == null) { + config = getConfiguration(true, null); + if (config == null) { + config = getConfiguration(false, name); + if (config == null) { + config = getConfiguration(false, null); + } + } + } + if (config != null) { + return config; + } + LOGGER.warn("No Log4j configuration file found. " + + "Using default configuration (logging only errors to the console), " + + "or user programmatically provided configurations. " + + "Set system property 'log4j2.{}.System.debug' " + + "to show Log4j internal initialization logging. " + + // TODO: update link for 3.x + "See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j", + loggerContext.getName()); + return new DefaultConfiguration(loggerContext); + } + + public Configuration getConfiguration(final String name, final URI configLocation, final ClassLoader loader) { + if (loader == null) { + return getConfiguration(name, configLocation); + } + if (ConfigurationFactory.isClassLoaderUri(configLocation)) { + final String path = ConfigurationFactory.extractClassLoaderUriPath(configLocation); + final Configuration configuration = configurationResolver.tryResolve(path, loader) + .map(this::getConfiguration) + .orElse(null); + if (configuration != null) { + return configuration; + } + } + return getConfiguration(name, configLocation); + } + + public Configuration getConfiguration(final ConfigurationSource source) { + if (source == null) { + LOGGER.error("Cannot process configuration, input source is null"); + return null; + } + final String config = source.getLocation(); + for (final ConfigurationFactory factory : factories) { + final String[] types = factory.getSupportedTypes(); + if (types != null) { + for (final String type : types) { + if (type.equals(ALL_TYPES) || config != null && config.endsWith(type)) { + final Configuration c = factory.getConfiguration(loggerContext, source); + if (c != null) { + LOGGER.debug("Loaded configuration from {}", source); + return c; + } + LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config); + return null; + } + } + } + } + LOGGER.error("Cannot process configuration at '{}'; no instance returned from any ConfigurationFactory", config); + return null; + } + + private Configuration getConfiguration(final String requiredVersion, final String configLocation) { + ConfigurationSource source = null; + try { + source = configurationResolver.tryResolve(NetUtils.toURI(configLocation)).orElse(null); + } catch (final Exception ex) { + // Ignore the error and try as a String. + LOGGER.catching(Level.DEBUG, ex); + } + if (source != null) { + for (final ConfigurationFactory factory : factories) { + if (requiredVersion != null && !factory.getVersion().equals(requiredVersion)) { + continue; + } + final String[] supportedTypes = factory.getSupportedTypes(); + if (supportedTypes != null) { + for (final String type : supportedTypes) { + if (type.equals(ALL_TYPES) || configLocation.endsWith(type)) { + final Configuration config = factory.getConfiguration(loggerContext, source); + if (config != null) { + return config; + } + } + } + } + } + } + return null; + } + + private Configuration getConfiguration(final boolean isTest, final String name) { + final boolean named = Strings.isNotEmpty(name); + final ClassLoader loader = LoaderUtil.getThreadContextClassLoader(); + for (final ConfigurationFactory factory : factories) { + String configName; + final String prefix = isTest ? factory.getTestPrefix() : factory.getDefaultPrefix(); + final String[] types = factory.getSupportedTypes(); + if (types == null) { + continue; + } + + for (final String suffix : types) { + if (suffix.equals(ALL_TYPES)) { + continue; + } + configName = named ? prefix + name + suffix : prefix + suffix; + + final ConfigurationSource source = configurationResolver.tryResolve(configName, loader).orElse(null); + if (source != null) { + if (!factory.isActive()) { + LOGGER.warn("Found configuration file {} for inactive ConfigurationFactory {}", configName, + factory.getClass().getName()); + } + return factory.getConfiguration(loggerContext, source); + } + } + } + return null; + } + + private static String[] parseConfigLocations(final URI configLocations) { + final String[] uris = configLocations.toString().split("\\?"); + final List locations = new ArrayList<>(); + if (uris.length > 1) { + locations.add(uris[0]); + final String[] pairs = configLocations.getQuery().split("&"); + for (final String pair : pairs) { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8) : pair; + if (key.equalsIgnoreCase(OVERRIDE_PARAM)) { + locations.add(URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8)); + } + } + return locations.toArray(new String[0]); + } + return new String[] { uris[0] }; + } + + private static String[] parseConfigLocations(final String configLocations) { + final String[] uris = configLocations.split(","); + if (uris.length > 1) { + return uris; + } + try { + return parseConfigLocations(new URI(configLocations)); + } catch (final URISyntaxException ex) { + LOGGER.warn("Error parsing URI {}", configLocations); + } + return new String[] { configLocations }; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationResolver.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationResolver.java new file mode 100644 index 00000000000..ca76071cf26 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationResolver.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Optional; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.net.UrlConnectionFactory; +import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.core.util.Loader; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.LoaderUtil; + +public class ConfigurationResolver { + private final Logger logger = StatusLogger.getLogger(); + private final UrlConnectionFactory urlConnectionFactory; + + @Inject + public ConfigurationResolver(final UrlConnectionFactory urlConnectionFactory) { + this.urlConnectionFactory = urlConnectionFactory; + } + + public ConfigurationSource resolve(final URL url) throws IOException, URISyntaxException { + final URLConnection urlConnection = urlConnectionFactory.openConnection(url); + urlConnection.connect(); + try { + final InputStream inputStream = urlConnection.getInputStream(); + final File file = FileUtils.fileFromUri(url.toURI()); + if (file != null) { + return new ConfigurationSource(inputStream, file); + } + return new ConfigurationSource(inputStream, url, urlConnection.getLastModified(), this); + } finally { + if (urlConnection instanceof HttpURLConnection) { + ((HttpURLConnection) urlConnection).disconnect(); + } + } + } + + public Optional tryResolve(final URL url) { + try { + return Optional.of(resolve(url)); + } catch (final IOException | URISyntaxException e) { + logger.warn("Error accessing {} due to {}, ignoring.", url, e.getMessage()); + return Optional.empty(); + } + } + + public Optional tryResolve(final String resource, final ClassLoader classLoader) { + return Optional.ofNullable(Loader.getResource(resource, classLoader)) + .flatMap(this::tryResolve); + } + + public Optional tryResolve(final URI uri) { + final File configFile = FileUtils.fileFromUri(uri); + if (configFile != null && configFile.exists() && configFile.canRead()) { + try { + return Optional.of(new ConfigurationSource(new FileInputStream(configFile), configFile)); + } catch (final FileNotFoundException e) { + logger.error("Cannot locate file {}", configFile); + } + } + if (ConfigurationFactory.isClassLoaderUri(uri)) { + final ClassLoader loader = LoaderUtil.getThreadContextClassLoader(); + final String path = ConfigurationFactory.extractClassLoaderUriPath(uri); + return tryResolve(path, loader); + } + if (!uri.isAbsolute()) { // LOG4J2-704 avoid confusing error message thrown by uri.toURL() + logger.error("File not found in file system or classpath: {}", uri); + return Optional.empty(); + } + try { + return tryResolve(uri.toURL()); + } catch (final MalformedURLException e) { + logger.error("Invalid configuration URL: {}", uri, e); + return Optional.empty(); + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java index e393d4c124e..ac10bbca458 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java @@ -28,11 +28,13 @@ import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.util.CronExpression; import org.apache.logging.log4j.core.util.Log4jThreadFactory; +import org.apache.logging.log4j.plugins.ConfigurationScoped; import org.apache.logging.log4j.status.StatusLogger; /** * */ +@ConfigurationScoped public class ConfigurationScheduler extends AbstractLifeCycle { private static final Logger LOGGER = StatusLogger.getLogger(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java index cc8b2752c7d..6c92d12eda8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java @@ -19,28 +19,15 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; -import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; -import javax.net.ssl.HttpsURLConnection; -import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier; -import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; -import org.apache.logging.log4j.core.util.AuthorizationProvider; -import org.apache.logging.log4j.core.util.FileUtils; -import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.Source; -import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertiesUtil; /** * Represents the source for the logging configuration. @@ -50,17 +37,17 @@ public class ConfigurationSource { /** * ConfigurationSource to use with Configurations that do not require a "real" configuration source. */ - public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0], null, 0); + public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0], null, 0, null); /** * ConfigurationSource to use with {@link org.apache.logging.log4j.core.config.composite.CompositeConfiguration}. */ - public static final ConfigurationSource COMPOSITE_SOURCE = new ConfigurationSource(new byte[0], null, 0); - private static final String HTTPS = "https"; - private static final String HTTP = "http"; + public static final ConfigurationSource COMPOSITE_SOURCE = new ConfigurationSource(new byte[0], null, 0, null); private final InputStream stream; private volatile byte[] data; - private volatile Source source; + private final Source source; + // Set when using a URL-based configuration for reloading + private final ConfigurationResolver configurationResolver; private final long lastModified; // Set when the configuration has been updated so reset can use it for the next lastModified timestamp. private volatile long modifiedMillis; @@ -76,6 +63,7 @@ public ConfigurationSource(final InputStream stream, final File file) { this.stream = Objects.requireNonNull(stream, "stream is null"); this.data = null; this.source = new Source(file); + this.configurationResolver = null; long modified = 0; try { modified = file.lastModified(); @@ -96,6 +84,7 @@ public ConfigurationSource(final InputStream stream, final Path path) { this.stream = Objects.requireNonNull(stream, "stream is null"); this.data = null; this.source = new Source(path); + this.configurationResolver = null; long modified = 0; try { modified = Files.getLastModifiedTime(path).toMillis(); @@ -113,10 +102,15 @@ public ConfigurationSource(final InputStream stream, final Path path) { * @param url the URL where the input stream originated */ public ConfigurationSource(final InputStream stream, final URL url) { + this(stream, url, null); + } + + public ConfigurationSource(final InputStream stream, final URL url, final ConfigurationResolver configurationResolver) { this.stream = Objects.requireNonNull(stream, "stream is null"); this.data = null; this.lastModified = 0; this.source = new Source(url); + this.configurationResolver = configurationResolver; } /** @@ -128,10 +122,16 @@ public ConfigurationSource(final InputStream stream, final URL url) { * @param lastModified when the source was last modified. */ public ConfigurationSource(final InputStream stream, final URL url, long lastModified) { + this(stream, url, lastModified, null); + } + + public ConfigurationSource(final InputStream stream, final URL url, long lastModified, + final ConfigurationResolver configurationResolver) { this.stream = Objects.requireNonNull(stream, "stream is null"); this.data = null; this.lastModified = lastModified; this.source = new Source(url); + this.configurationResolver = configurationResolver; } /** @@ -142,7 +142,7 @@ public ConfigurationSource(final InputStream stream, final URL url, long lastMod * @throws IOException if an exception occurred reading from the specified stream */ public ConfigurationSource(final InputStream stream) throws IOException { - this(stream.readAllBytes(), null, 0); + this(stream.readAllBytes(), null, 0, null); } public ConfigurationSource(final Source source, final byte[] data, final long lastModified) throws IOException { @@ -151,17 +151,15 @@ public ConfigurationSource(final Source source, final byte[] data, final long la this.stream = new ByteArrayInputStream(data); this.lastModified = lastModified; this.source = source; + this.configurationResolver = null; } - private ConfigurationSource(final byte[] data, final URL url, final long lastModified) { + private ConfigurationSource(final byte[] data, final URL url, final long lastModified, final ConfigurationResolver configurationResolver) { this.data = Objects.requireNonNull(data, "data is null"); this.stream = new ByteArrayInputStream(data); this.lastModified = lastModified; - if (url == null) { - this.data = data; - } else { - this.source = new Source(url); - } + this.source = url == null ? null : new Source(url); + this.configurationResolver = configurationResolver; } /** @@ -175,15 +173,15 @@ public File getFile() { } private boolean isFile() { - return source == null ? false : source.getFile() != null; + return source != null && source.getFile() != null; } private boolean isURL() { - return source == null ? false : source.getURI() != null; + return source != null && source.getURI() != null; } private boolean isLocation() { - return source == null ? false : source.getLocation() != null; + return source != null && source.getLocation() != null; } /** @@ -196,14 +194,6 @@ public URL getURL() { return source == null ? null : source.getURL(); } - /** - * @deprecated Not used internally, no replacement. TODO remove and make source final. - */ - @Deprecated - public void setSource(Source source) { - this.source = source; - } - public void setData(final byte[] data) { this.data = data; } @@ -260,11 +250,11 @@ public ConfigurationSource resetInputStream() throws IOException { return new ConfigurationSource(new FileInputStream(getFile()), getFile()); } else if (isURL() && data != null) { // Creates a ConfigurationSource without accessing the URL since the data was provided. - return new ConfigurationSource(data, getURL(), modifiedMillis == 0 ? lastModified : modifiedMillis); + return new ConfigurationSource(data, getURL(), modifiedMillis == 0 ? lastModified : modifiedMillis, configurationResolver); } else if (isURL()) { - return fromUri(getURI()); + return configurationResolver.tryResolve(getURI()).orElse(null); } else if (data != null) { - return new ConfigurationSource(data, null, lastModified); + return new ConfigurationSource(data, null, lastModified, configurationResolver); } return null; } @@ -284,82 +274,4 @@ public String toString() { return "stream (" + length + " bytes, unknown location)"; } - /** - * Loads the configuration from a URI. - * @param configLocation A URI representing the location of the configuration. - * @return The ConfigurationSource for the configuration. - */ - public static ConfigurationSource fromUri(final URI configLocation) { - final File configFile = FileUtils.fileFromUri(configLocation); - if (configFile != null && configFile.exists() && configFile.canRead()) { - try { - return new ConfigurationSource(new FileInputStream(configFile), configFile); - } catch (final FileNotFoundException ex) { - ConfigurationFactory.LOGGER.error("Cannot locate file {}", configLocation.getPath(), ex); - } - } - if (ConfigurationFactory.isClassLoaderUri(configLocation)) { - final ClassLoader loader = LoaderUtil.getThreadContextClassLoader(); - final String path = ConfigurationFactory.extractClassLoaderUriPath(configLocation); - return fromResource(path, loader); - } - if (!configLocation.isAbsolute()) { // LOG4J2-704 avoid confusing error message thrown by uri.toURL() - ConfigurationFactory.LOGGER.error("File not found in file system or classpath: {}", configLocation.toString()); - return null; - } - try { - return getConfigurationSource(configLocation.toURL()); - } catch (final MalformedURLException ex) { - ConfigurationFactory.LOGGER.error("Invalid URL {}", configLocation.toString(), ex); - } - return null; - } - - /** - * Retrieves the configuration via the ClassLoader. - * @param resource The resource to load. - * @param loader The default ClassLoader to use. - * @return The ConfigurationSource for the configuration. - */ - public static ConfigurationSource fromResource(final String resource, final ClassLoader loader) { - final URL url = Loader.getResource(resource, loader); - if (url == null) { - return null; - } - return getConfigurationSource(url); - } - - private static ConfigurationSource getConfigurationSource(final URL url) { - try { - final URLConnection urlConnection = url.openConnection(); - // A "jar:" URL file remains open after the stream is closed, so do not cache it. - urlConnection.setUseCaches(false); - final AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties()); - provider.addAuthorization(urlConnection); - if (url.getProtocol().equals(HTTPS)) { - final SslConfiguration sslConfiguration = SslConfigurationFactory.getSslConfiguration(); - if (sslConfiguration != null) { - ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory()); - if (!sslConfiguration.isVerifyHostName()) { - ((HttpsURLConnection) urlConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE); - } - } - } - final File file = FileUtils.fileFromUri(url.toURI()); - try { - if (file != null) { - return new ConfigurationSource(urlConnection.getInputStream(), FileUtils.fileFromUri(url.toURI())); - } else { - return new ConfigurationSource(urlConnection.getInputStream(), url, urlConnection.getLastModified()); - } - } catch (final FileNotFoundException ex) { - ConfigurationFactory.LOGGER.info("Unable to locate file {}, ignoring.", url.toString()); - return null; - } - } catch (final IOException | URISyntaxException ex) { - ConfigurationFactory.LOGGER.warn("Error accessing {} due to {}, ignoring.", url.toString(), - ex.getMessage()); - return null; - } - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java index 96e7c1fd4ed..e833913d052 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java @@ -408,7 +408,12 @@ private static boolean setLevel(final String loggerName, final Level level, fina LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); if (!loggerName.equals(loggerConfig.getName())) { // TODO Should additivity be inherited? - loggerConfig = new LoggerConfig(loggerName, level, true); + loggerConfig = LoggerConfig.newBuilder() + .setLoggerName(loggerName) + .setLevel(level) + .setAdditivity(true) + .setConfig(config) + .get(); config.addLogger(loggerName, loggerConfig); loggerConfig.setLevel(level); set = true; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java index ea315e49c0c..471e2c8593e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.config; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.Log4jProperties; /** @@ -45,7 +46,11 @@ public class DefaultConfiguration extends AbstractConfiguration { * Constructor to create the default configuration. */ public DefaultConfiguration() { - super(null, ConfigurationSource.NULL_SOURCE); + this(LoggerContext.getContext()); + } + + public DefaultConfiguration(final LoggerContext loggerContext) { + super(loggerContext, ConfigurationSource.NULL_SOURCE); setToDefault(); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java index 9d5e9a5f5e7..08e6936a36f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java @@ -17,219 +17,18 @@ package org.apache.logging.log4j.core.config; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; -import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Loader; -import org.apache.logging.log4j.core.util.NetUtils; -import org.apache.logging.log4j.plugins.Inject; -import org.apache.logging.log4j.plugins.di.Injector; -import org.apache.logging.log4j.spi.LoggingSystemProperties; -import org.apache.logging.log4j.util.Lazy; -import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; -import org.apache.logging.log4j.util.Strings; /** - * Default factory for using a plugin selected based on the configuration source. + * Default implementation of {@link ConfigurationFactory} which dynamically selects a factory from installed plugins + * that supports a given configuration source. */ public class DefaultConfigurationFactory extends ConfigurationFactory { - private static final String ALL_TYPES = "*"; - private static final String OVERRIDE_PARAM = "override"; - - private final Lazy> configurationFactories; - - @Inject - public DefaultConfigurationFactory(final Injector injector) { - configurationFactories = Lazy.lazy(() -> loadConfigurationFactories(injector)); - } - - /** - * Default Factory Constructor. - * - * @param name The configuration name. - * @param configLocation The configuration location. - * @return The Configuration. - */ @Override public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) { - - if (configLocation == null) { - final PropertyEnvironment properties = PropertiesUtil.getProperties(); - final String configLocationStr = substitutor.replace(properties.getStringProperty(CONFIGURATION_FILE_PROPERTY)); - if (configLocationStr != null) { - final String[] sources = parseConfigLocations(configLocationStr); - if (sources.length > 1) { - final List configs = new ArrayList<>(); - for (final String sourceLocation : sources) { - final Configuration config = getConfiguration(loggerContext, sourceLocation.trim()); - if (config != null) { - if (config instanceof AbstractConfiguration) { - configs.add((AbstractConfiguration) config); - } else { - LOGGER.error("Failed to created configuration at {}", sourceLocation); - return null; - } - } else { - LOGGER.warn("Unable to create configuration for {}, ignoring", sourceLocation); - } - } - if (configs.size() > 1) { - return new CompositeConfiguration(configs); - } else if (configs.size() == 1) { - return configs.get(0); - } - } - return getConfiguration(loggerContext, configLocationStr); - } else { - final String log4j1ConfigStr = - substitutor.replace(properties.getStringProperty(LOG4J1_CONFIGURATION_FILE_PROPERTY)); - if (log4j1ConfigStr != null) { - System.setProperty(LOG4J1_EXPERIMENTAL, "true"); - return getConfiguration(LOG4J1_VERSION, loggerContext, log4j1ConfigStr); - } - } - for (final ConfigurationFactory factory : configurationFactories.value()) { - final String[] types = factory.getSupportedTypes(); - if (types != null) { - for (final String type : types) { - if (type.equals(ALL_TYPES)) { - final Configuration config = factory.getConfiguration(loggerContext, name, null); - if (config != null) { - return config; - } - } - } - } - } - } else { - // configLocation != null - final String[] sources = parseConfigLocations(configLocation); - if (sources.length > 1) { - final List configs = new ArrayList<>(); - for (final String sourceLocation : sources) { - final Configuration config = getConfiguration(loggerContext, sourceLocation.trim()); - if (config instanceof AbstractConfiguration) { - configs.add((AbstractConfiguration) config); - } else { - LOGGER.error("Failed to created configuration at {}", sourceLocation); - return null; - } - } - return new CompositeConfiguration(configs); - } - final String configLocationStr = configLocation.toString(); - for (final ConfigurationFactory factory : configurationFactories.value()) { - final String[] types = factory.getSupportedTypes(); - if (types != null) { - for (final String type : types) { - if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) { - final Configuration config = factory.getConfiguration(loggerContext, name, configLocation); - if (config != null) { - return config; - } - } - } - } - } - } - - Configuration config = getConfiguration(loggerContext, true, name); - if (config == null) { - config = getConfiguration(loggerContext, true, null); - if (config == null) { - config = getConfiguration(loggerContext, false, name); - if (config == null) { - config = getConfiguration(loggerContext, false, null); - } - } - } - if (config != null) { - return config; - } - LOGGER.warn("No Log4j 2 configuration file found. " + - "Using default configuration (logging only errors to the console), " + - "or user programmatically provided configurations. " + - "Set system property 'log4j2.*.{}' " + - "to show Log4j 2 internal initialization logging. " + - "See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2", - LoggingSystemProperties.SYSTEM_DEBUG); - return new DefaultConfiguration(); - } - - private Configuration getConfiguration(final LoggerContext loggerContext, final String configLocationStr) { - return getConfiguration(null, loggerContext, configLocationStr); - } - - private Configuration getConfiguration( - final String requiredVersion, final LoggerContext loggerContext, - final String configLocationStr) { - ConfigurationSource source = null; - try { - source = ConfigurationSource.fromUri(NetUtils.toURI(configLocationStr)); - } catch (final Exception ex) { - // Ignore the error and try as a String. - LOGGER.catching(Level.DEBUG, ex); - } - if (source != null) { - for (final ConfigurationFactory factory : configurationFactories.value()) { - if (requiredVersion != null && !factory.getVersion().equals(requiredVersion)) { - continue; - } - final String[] types = factory.getSupportedTypes(); - if (types != null) { - for (final String type : types) { - if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) { - final Configuration config = factory.getConfiguration(loggerContext, source); - if (config != null) { - return config; - } - } - } - } - } - } - return null; - } - - private Configuration getConfiguration(final LoggerContext loggerContext, final boolean isTest, final String name) { - final boolean named = Strings.isNotEmpty(name); - final ClassLoader loader = LoaderUtil.getThreadContextClassLoader(); - for (final ConfigurationFactory factory : configurationFactories.value()) { - String configName; - final String prefix = isTest ? factory.getTestPrefix() : factory.getDefaultPrefix(); - final String[] types = factory.getSupportedTypes(); - if (types == null) { - continue; - } - - for (final String suffix : types) { - if (suffix.equals(ALL_TYPES)) { - continue; - } - configName = named ? prefix + name + suffix : prefix + suffix; - - final ConfigurationSource source = ConfigurationSource.fromResource(configName, loader); - if (source != null) { - if (!factory.isActive()) { - LOGGER.warn("Found configuration file {} for inactive ConfigurationFactory {}", configName, - factory.getClass().getName()); - } - return factory.getConfiguration(loggerContext, source); - } - } - } - return null; + return getProvider(loggerContext).getConfiguration(name, configLocation); } @Override @@ -239,101 +38,12 @@ public String[] getSupportedTypes() { @Override public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { - if (source != null) { - final String config = source.getLocation(); - for (final ConfigurationFactory factory : configurationFactories.value()) { - final String[] types = factory.getSupportedTypes(); - if (types != null) { - for (final String type : types) { - if (type.equals(ALL_TYPES) || config != null && config.endsWith(type)) { - final Configuration c = factory.getConfiguration(loggerContext, source); - if (c != null) { - LOGGER.debug("Loaded configuration from {}", source); - return c; - } - LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config); - return null; - } - } - } - } - } - LOGGER.error("Cannot process configuration, input source is null"); - return null; - } - - private String[] parseConfigLocations(final URI configLocations) { - final String[] uris = configLocations.toString().split("\\?"); - final List locations = new ArrayList<>(); - if (uris.length > 1) { - locations.add(uris[0]); - final String[] pairs = configLocations.getQuery().split("&"); - for (final String pair : pairs) { - final int idx = pair.indexOf("="); - final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8) : pair; - if (key.equalsIgnoreCase(OVERRIDE_PARAM)) { - locations.add(URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8)); - } - } - return locations.toArray(new String[0]); - } - return new String[] { uris[0] }; + return getProvider(loggerContext).getConfiguration(source); } - private String[] parseConfigLocations(final String configLocations) { - final String[] uris = configLocations.split(","); - if (uris.length > 1) { - return uris; - } - try { - return parseConfigLocations(new URI(configLocations)); - } catch (final URISyntaxException ex) { - LOGGER.warn("Error parsing URI {}", configLocations); - } - return new String[] { configLocations }; + private static ConfigurationProvider getProvider(final LoggerContext loggerContext) { + final LoggerContext context = loggerContext != null ? loggerContext : LoggerContext.getContext(); + return context.getInstance(ConfigurationProvider.class); } - private static List loadConfigurationFactories(final Injector injector) { - final List factories = new ArrayList<>(); - - Optional.ofNullable(PropertiesUtil.getProperties().getStringProperty(Log4jProperties.CONFIG_CONFIGURATION_FACTORY_CLASS_NAME)) - .flatMap(DefaultConfigurationFactory::tryLoadFactoryClass) - .map(clazz -> { - try { - return injector.getInstance(clazz); - } catch (final Exception ex) { - LOGGER.error("Unable to create instance of {}", clazz, ex); - return null; - } - }) - .ifPresent(factories::add); - - final List> configurationFactoryPluginClasses = new ArrayList<>(); - injector.getInstance(PLUGIN_CATEGORY_KEY).forEach(type -> { - try { - configurationFactoryPluginClasses.add(type.getPluginClass().asSubclass(ConfigurationFactory.class)); - } catch (final Exception ex) { - LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex); - } - }); - configurationFactoryPluginClasses.sort(OrderComparator.getInstance()); - configurationFactoryPluginClasses.forEach(clazz -> { - try { - factories.add(injector.getInstance(clazz)); - } catch (final Exception ex) { - LOGGER.error("Unable to create instance of {}", clazz, ex); - } - }); - - return factories; - } - - private static Optional> tryLoadFactoryClass(final String factoryClass) { - try { - return Optional.of(Loader.loadClass(factoryClass).asSubclass(ConfigurationFactory.class)); - } catch (final Exception ex) { - LOGGER.error("Unable to load ConfigurationFactory class {}", factoryClass, ex); - return Optional.empty(); - } - } } diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLoggerContextNamingStrategy.java similarity index 63% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLoggerContextNamingStrategy.java index 16b945c09b7..192548cbe51 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLoggerContextNamingStrategy.java @@ -14,18 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.core.config; -import java.util.function.Consumer; -import java.util.function.Supplier; +import java.net.URI; +import java.util.Map; -@FunctionalInterface -public interface RecyclerFactory { +import org.apache.logging.log4j.util.PropertyResolver; - default Recycler create(final Supplier supplier) { - return create(supplier, ignored -> {}); +public class DefaultLoggerContextNamingStrategy implements LoggerContextNamingStrategy { + @Override + public String getName(final URI configLocation, final ClassLoader classLoader, final Object externalContext, + final Map.Entry entry) { + return PropertyResolver.DEFAULT_CONTEXT; } - - Recycler create(Supplier supplier, Consumer cleaner); - } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java index 7d29dd4f6fe..25ae37ed823 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java @@ -23,19 +23,16 @@ import java.util.List; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; import org.apache.logging.log4j.core.util.AbstractWatcher; -import org.apache.logging.log4j.core.util.AuthorizationProvider; import org.apache.logging.log4j.core.util.Source; import org.apache.logging.log4j.core.util.Watcher; -import org.apache.logging.log4j.core.util.internal.HttpInputStreamUtil; +import org.apache.logging.log4j.core.util.internal.HttpResponse; +import org.apache.logging.log4j.core.util.internal.HttpSourceLoader; import org.apache.logging.log4j.core.util.internal.LastModifiedSource; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginAliases; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; /** * @@ -47,18 +44,17 @@ public class HttpWatcher extends AbstractWatcher { private final Logger LOGGER = StatusLogger.getLogger(); - private final SslConfiguration sslConfiguration; - private AuthorizationProvider authorizationProvider; private URL url; - private volatile long lastModifiedMillis; + private final long lastModifiedMillis; + private final HttpSourceLoader httpSourceLoader; private static final String HTTP = "http"; private static final String HTTPS = "https"; public HttpWatcher(final Configuration configuration, final Reconfigurable reconfigurable, final List configurationListeners, final long lastModifiedMillis) { super(configuration, reconfigurable, configurationListeners); - sslConfiguration = SslConfigurationFactory.getSslConfiguration(); this.lastModifiedMillis = lastModifiedMillis; + this.httpSourceLoader = configuration.getInstance(HttpSourceLoader.class); } @Override @@ -79,7 +75,6 @@ public void watching(final Source source) { } try { url = source.getURI().toURL(); - authorizationProvider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties()); } catch (final MalformedURLException ex) { throw new IllegalArgumentException("Invalid URL for HttpWatcher " + source.getURI(), ex); } @@ -99,8 +94,8 @@ public Watcher newWatcher(final Reconfigurable reconfigurable, final List appenderRefs = new ArrayList<>(); + private final List appenderRefs; private final AppenderControlArraySet appenders = new AppenderControlArraySet(); private final String name; private LogEventFactory logEventFactory; private Level level; - private boolean additive = true; - private boolean includeLocation = true; + private boolean additive; + private final boolean includeLocation; private LoggerConfig parent; - private Map propertiesMap; + private final PropertyResolver propertyResolver; private final List properties; private final boolean propertiesRequireLookup; private final Configuration config; @@ -101,12 +100,13 @@ public static class Builder> private Configuration config; private Filter filter; private LogEventFactory logEventFactory; + private PropertyResolver propertyResolver; public boolean isAdditivity() { return additivity == null || additivity; } - public B withAdditivity(boolean additivity) { + public B setAdditivity(boolean additivity) { this.additivity = additivity; return asBuilder(); } @@ -115,7 +115,7 @@ public Level getLevel() { return level; } - public B withLevel(@PluginAttribute Level level) { + public B setLevel(@PluginAttribute Level level) { this.level = level; return asBuilder(); } @@ -124,7 +124,7 @@ public String getLevelAndRefs() { return levelAndRefs; } - public B withLevelAndRefs(@PluginAttribute String levelAndRefs) { + public B setLevelAndRefs(@PluginAttribute String levelAndRefs) { this.levelAndRefs = levelAndRefs; return asBuilder(); } @@ -133,7 +133,7 @@ public String getLoggerName() { return loggerName; } - public B withLoggerName( + public B setLoggerName( @Required(message = "Loggers cannot be configured without a name") @PluginAttribute String name) { this.loggerName = name; return asBuilder(); @@ -143,7 +143,7 @@ public String getIncludeLocation() { return includeLocation; } - public B withIncludeLocation(@PluginAttribute String includeLocation) { + public B setIncludeLocation(@PluginAttribute String includeLocation) { this.includeLocation = includeLocation; return asBuilder(); } @@ -152,7 +152,7 @@ public AppenderRef[] getRefs() { return refs; } - public B withRefs(@PluginElement AppenderRef[] refs) { + public B setRefs(@PluginElement AppenderRef[] refs) { this.refs = refs; return asBuilder(); } @@ -161,7 +161,7 @@ public Property[] getProperties() { return properties; } - public B withProperties(@PluginElement Property[] properties) { + public B setProperties(@PluginElement Property[] properties) { this.properties = properties; return asBuilder(); } @@ -170,7 +170,7 @@ public Configuration getConfig() { return config; } - public B withConfig(@PluginConfiguration Configuration config) { + public B setConfig(@PluginConfiguration Configuration config) { this.config = config; return asBuilder(); } @@ -179,12 +179,15 @@ public Filter getFilter() { return filter; } - public B withFilter(@PluginElement Filter filter) { + public B setFilter(@PluginElement Filter filter) { this.filter = filter; return asBuilder(); } public LogEventFactory getLogEventFactory() { + if (logEventFactory == null) { + logEventFactory = config.getInstance(LogEventFactory.KEY); + } return logEventFactory; } @@ -194,56 +197,39 @@ public B setLogEventFactory(LogEventFactory logEventFactory) { return asBuilder(); } + public PropertyResolver getPropertyResolver() { + if (propertyResolver == null) { + propertyResolver = config.getPropertyResolver(); + } + return propertyResolver; + } + + @Inject + public B setPropertyResolver(final PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + return asBuilder(); + } + @Override public LoggerConfig build() { + final Configuration configuration = Objects.requireNonNull(config, "No Configuration provided"); final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; - LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, config); - boolean useLocation = includeLocation(includeLocation, config); - return new LoggerConfig(name, container.refs, filter, container.level, isAdditivity(), properties, config, - useLocation, logEventFactory); + LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, configuration); + boolean useLocation = includeLocation(includeLocation, configuration); + return new LoggerConfig(name, container.refs, filter, container.level, isAdditivity(), properties, + configuration, useLocation, getLogEventFactory(), getPropertyResolver()); } - @SuppressWarnings("unchecked") public B asBuilder() { - return (B) this; + return Cast.cast(this); } } - /** - * Default constructor. - */ - public LoggerConfig() { - this.logEventFactory = DefaultLogEventFactory.newInstance(); - this.level = Level.ERROR; - this.name = Strings.EMPTY; - this.properties = null; - this.propertiesRequireLookup = false; - this.config = null; - this.reliabilityStrategy = new DefaultReliabilityStrategy(this); - } - - /** - * Constructor that sets the name, level and additive values. - * - * @param name The Logger name. - * @param level The Level. - * @param additive true if the Logger is additive, false otherwise. - */ - public LoggerConfig(final String name, final Level level, final boolean additive) { - this.logEventFactory = DefaultLogEventFactory.newInstance(); - this.name = name; - this.level = level; - this.additive = additive; - this.properties = null; - this.propertiesRequireLookup = false; - this.config = null; - this.reliabilityStrategy = new DefaultReliabilityStrategy(this); - } - protected LoggerConfig( final String name, final List appenders, final Filter filter, final Level level, final boolean additive, final Property[] properties, final Configuration config, - final boolean includeLocation, final LogEventFactory logEventFactory) { + final boolean includeLocation, final LogEventFactory logEventFactory, + final PropertyResolver propertyResolver) { super(filter, null); this.logEventFactory = logEventFactory; this.name = name; @@ -251,14 +237,16 @@ protected LoggerConfig( this.level = level; this.additive = additive; this.includeLocation = includeLocation; - this.config = config; + this.config = Objects.requireNonNull(config, "No Configuration provided"); + this.propertyResolver = propertyResolver; if (properties != null && properties.length > 0) { this.properties = List.of(properties.clone()); } else { this.properties = null; } this.propertiesRequireLookup = containsPropertyRequiringLookup(properties); - this.reliabilityStrategy = config.getReliabilityStrategy(this); + this.reliabilityStrategy = config.getInstance(ReliabilityStrategyFactory.class) + .getReliabilityStrategy(this); } private static boolean containsPropertyRequiringLookup(final Property[] properties) { @@ -458,6 +446,10 @@ public boolean isPropertiesRequireLookup() { return propertiesRequireLookup; } + public PropertyResolver getPropertyResolver() { + return propertyResolver; + } + /** * Logs an event. * @@ -534,21 +526,20 @@ private List getPropertiesWithLookups( final Throwable t, final List props) { List results = new ArrayList<>(props.size()); - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setMessage(data) .setMarker(marker) .setLevel(level) .setLoggerName(loggerName) .setLoggerFqcn(fqcn) .setThrown(t) - .build(); - for (int i = 0; i < props.size(); i++) { - final Property prop = props.get(i); + .get(); + props.forEach(prop -> { final String value = prop.isValueNeedsLookup() // since LOG4J2-1575 ? config.getStrSubstitutor().replace(event, prop.getValue()) // : prop.getValue(); results.add(Property.createProperty(prop.getName(), value)); - } + }); return results; } @@ -636,29 +627,6 @@ public String toString() { return Strings.isEmpty(name) ? ROOT : name; } - /** - * Factory method to create a LoggerConfig. - * - * @param additivity true if additive, false otherwise. - * @param level The Level to be associated with the Logger. - * @param loggerName The name of the Logger. - * @param includeLocation whether location should be passed downstream - * @param refs An array of Appender names. - * @param properties Properties to pass to the Logger. - * @param config The Configuration. - * @param filter A Filter. - * @return A new LoggerConfig. - * @since 2.6 - */ - @Deprecated - public static LoggerConfig createLogger( - final boolean additivity, final Level level, final String loggerName, final String includeLocation, - final AppenderRef[] refs, final Property[] properties, final Configuration config, final Filter filter) { - final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; - return new LoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config, - includeLocation(includeLocation, config), config.getComponent(LogEventFactory.KEY)); - } - // Note: for asynchronous loggers, includeLocation default is FALSE, // for synchronous loggers, includeLocation default is TRUE. protected static boolean includeLocation(final String includeLocationConfigValue, final Configuration configuration) { @@ -669,8 +637,6 @@ protected static boolean includeLocation(final String includeLocationConfigValue } if (context != null) { return !(context instanceof AsyncLoggerContext); - } else { - return !AsyncLoggerContextSelector.isSelected(); } } return Boolean.parseBoolean(includeLocationConfigValue); @@ -686,6 +652,13 @@ protected final boolean hasAppenders() { @Configurable(printObject = true) @Plugin(ROOT) public static class RootLogger extends LoggerConfig { + private RootLogger(final List appenders, final Filter filter, final Level level, + final boolean additive, final Property[] properties, final Configuration config, + final boolean includeLocation, final LogEventFactory logEventFactory, + final PropertyResolver propertyResolver) { + super(LogManager.ROOT_LOGGER_NAME, appenders, filter, level, additive, properties, config, + includeLocation, logEventFactory, propertyResolver); + } @PluginFactory public static > B newRootBuilder() { @@ -710,12 +683,13 @@ public static class Builder> private Configuration config; private Filter filter; private LogEventFactory logEventFactory; + private PropertyResolver propertyResolver; public boolean isAdditivity() { return additivity; } - public B withAdditivity(@PluginAttribute boolean additivity) { + public B setAdditivity(@PluginAttribute boolean additivity) { this.additivity = additivity; return asBuilder(); } @@ -724,7 +698,7 @@ public Level getLevel() { return level; } - public B withLevel(@PluginAttribute Level level) { + public B setLevel(@PluginAttribute Level level) { this.level = level; return asBuilder(); } @@ -733,7 +707,7 @@ public String getLevelAndRefs() { return levelAndRefs; } - public B withLevelAndRefs(@PluginAttribute String levelAndRefs) { + public B setLevelAndRefs(@PluginAttribute String levelAndRefs) { this.levelAndRefs = levelAndRefs; return asBuilder(); } @@ -742,7 +716,7 @@ public String getIncludeLocation() { return includeLocation; } - public B withIncludeLocation(@PluginAttribute String includeLocation) { + public B setIncludeLocation(@PluginAttribute String includeLocation) { this.includeLocation = includeLocation; return asBuilder(); } @@ -751,7 +725,7 @@ public AppenderRef[] getRefs() { return refs; } - public B withRefs(@PluginElement AppenderRef[] refs) { + public B setRefs(@PluginElement AppenderRef[] refs) { this.refs = refs; return asBuilder(); } @@ -760,7 +734,7 @@ public Property[] getProperties() { return properties; } - public B withProperties(@PluginElement Property[] properties) { + public B setProperties(@PluginElement Property[] properties) { this.properties = properties; return asBuilder(); } @@ -769,7 +743,7 @@ public Configuration getConfig() { return config; } - public B withConfig(@PluginConfiguration Configuration config) { + public B setConfig(@PluginConfiguration Configuration config) { this.config = config; return asBuilder(); } @@ -778,47 +752,49 @@ public Filter getFilter() { return filter; } - public B withFilter(@PluginElement Filter filter) { + public B setFilter(@PluginElement Filter filter) { this.filter = filter; return asBuilder(); } public LogEventFactory getLogEventFactory() { + if (logEventFactory == null) { + logEventFactory = config.getInstance(LogEventFactory.class); + } return logEventFactory; } @Inject - public B withLogEventFactory(final LogEventFactory logEventFactory) { + public B setLogEventFactory(final LogEventFactory logEventFactory) { this.logEventFactory = logEventFactory; return asBuilder(); } + public PropertyResolver getPropertyResolver() { + if (propertyResolver == null) { + propertyResolver = config.getPropertyResolver(); + } + return propertyResolver; + } + + @Inject + public B setPropertyResolver(final PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + return asBuilder(); + } + @Override public LoggerConfig build() { - LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, config); - return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, container.refs, filter, container.level, - additivity, properties, config, includeLocation(includeLocation, config), logEventFactory); + final Configuration configuration = Objects.requireNonNull(config, "No Configuration provided"); + LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, configuration); + return new RootLogger(container.refs, filter, container.level, additivity, properties, configuration, + includeLocation(includeLocation, configuration), getLogEventFactory(), getPropertyResolver()); } - @SuppressWarnings("unchecked") public B asBuilder() { - return (B) this; + return Cast.cast(this); } } - - - @Deprecated - public static LoggerConfig createLogger( - final String additivity, final Level level, final String includeLocation, final AppenderRef[] refs, - final Property[] properties, final Configuration config, final Filter filter) { - final List appenderRefs = Arrays.asList(refs); - final Level actualLevel = level == null ? Level.ERROR : level; - final boolean additive = Booleans.parseBoolean(additivity, true); - - return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive, - properties, config, includeLocation(includeLocation, config), - config.getComponent(LogEventFactory.KEY)); - } } protected static LevelAndRefs getLevelAndRefs(Level level, AppenderRef[] refs, String levelAndRefs, diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/Recycler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextNamingStrategy.java similarity index 72% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/Recycler.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextNamingStrategy.java index 6e6924b366b..a42410dbd1d 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/Recycler.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextNamingStrategy.java @@ -14,12 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.core.config; -public interface Recycler { - - V acquire(); - - void release(V value); +import java.net.URI; +import java.util.Map; +public interface LoggerContextNamingStrategy { + String getName(final URI configLocation, final ClassLoader classLoader, final Object externalContext, + final Map.Entry entry); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java index db6f779a450..ac4e3ed6cd3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java @@ -16,24 +16,282 @@ */ package org.apache.logging.log4j.core.config; +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.AbstractLifeCycle; +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.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate; +import org.apache.logging.log4j.core.async.AsyncWaitStrategyFactory; +import org.apache.logging.log4j.core.filter.DenyAllFilter; +import org.apache.logging.log4j.core.lookup.Interpolator; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.apache.logging.log4j.core.net.Advertiser; +import org.apache.logging.log4j.core.script.ScriptManager; +import org.apache.logging.log4j.core.time.NanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.apache.logging.log4j.core.util.WatchManager; +import org.apache.logging.log4j.plugins.ConfigurationScoped; +import org.apache.logging.log4j.plugins.Node; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.Key; +import org.apache.logging.log4j.plugins.di.SimpleScope; +import org.apache.logging.log4j.util.PropertyResolver; /** * This configuration defaults to no logging. */ -public class NullConfiguration extends AbstractConfiguration { +public class NullConfiguration extends AbstractLifeCycle implements Configuration { /** * Name of this configuration. */ public static final String NULL_NAME = "Null"; + private final WeakReference loggerContextRef; + private final Injector injector; + private final PropertyResolver propertyResolver; + private final LoggerConfig rootLoggerConfig; + private final Filter filter = DenyAllFilter.newBuilder().get(); + private final Advertiser advertiser = new DefaultAdvertiser(); + private final StrSubstitutor strSubstitutor; + private final NanoClock nanoClock = new DummyNanoClock(); + public NullConfiguration() { - super(null, ConfigurationSource.NULL_SOURCE); + this(NullLoggerContext.getInstance()); + } + + public NullConfiguration(final LoggerContext loggerContext) { + loggerContextRef = new WeakReference<>(loggerContext); + injector = loggerContext.getInjector().copy(); + injector.registerScope(ConfigurationScoped.class, new SimpleScope(() -> "ConfigurationScoped; name=Null")); + propertyResolver = loggerContext.getPropertyResolver(); + rootLoggerConfig = LoggerConfig.RootLogger.newRootBuilder() + .setLevel(Level.OFF) + .setConfig(this) + .setPropertyResolver(propertyResolver) + .get(); + final Interpolator interpolator = new Interpolator(); + interpolator.setLoggerContext(loggerContext); + strSubstitutor = new StrSubstitutor(interpolator); + strSubstitutor.setConfiguration(this); + } + + @Override + public String getName() { + return NULL_NAME; + } + + @Override + public LoggerConfig getLoggerConfig(final String name) { + return rootLoggerConfig; + } + + @Override + public T getAppender(final String name) { + return null; + } + + @Override + public Map getAppenders() { + return Map.of(); + } + + @Override + public void addAppender(final Appender appender) { + // no-op + } + + @Override + public Map getLoggers() { + return Map.of(rootLoggerConfig.getName(), rootLoggerConfig); + } + + @Override + public void addLoggerAppender(final Logger logger, final Appender appender) { + // no-op + } + + @Override + public void addLoggerFilter(final Logger logger, final Filter filter) { + // no-op + } + + @Override + public void setLoggerAdditive(final Logger logger, final boolean additive) { + // no-op + } + + @Override + public void addLogger(final String name, final LoggerConfig loggerConfig) { + // no-op + } + + @Override + public void removeLogger(final String name) { + // no-op + } + + @Override + public Map getProperties() { + return Map.of(); + } + + @Override + public PropertyResolver getPropertyResolver() { + return propertyResolver; + } + + @Override + public LoggerConfig getRootLogger() { + return rootLoggerConfig; + } + + @Override + public void addListener(final ConfigurationListener listener) { + // no-op + } + + @Override + public void removeListener(final ConfigurationListener listener) { + // no-op + } + + @Override + public StrSubstitutor getStrSubstitutor() { + return strSubstitutor; + } + + @Override + public void createConfiguration(final Node node, final LogEvent event) { + // no-op + } + + @Override + public T getInstance(final Class type) { + return injector.getInstance(type); + } - setName(NULL_NAME); - final LoggerConfig root = getRootLogger(); - root.setLevel(Level.OFF); + @Override + public Optional tryGetInstance(final Class type) { + return injector.tryGetInstance(type); } + @Override + public T getInstance(final Key key) { + return injector.getInstance(key); + } + + @Override + public T getComponent(final String name) { + return null; + } + + @Override + public void addComponent(final String name, final Object object) { + // no-op + } + + @Override + public void setAdvertiser(final Advertiser advertiser) { + // no-op + } + + @Override + public Advertiser getAdvertiser() { + return advertiser; + } + + @Override + public boolean isShutdownHookEnabled() { + return false; + } + + @Override + public long getShutdownTimeoutMillis() { + return 0; + } + + @Override + public ConfigurationScheduler getScheduler() { + return getInstance(ConfigurationScheduler.class); + } + + @Override + public ConfigurationSource getConfigurationSource() { + return ConfigurationSource.NULL_SOURCE; + } + + @Override + public List getCustomLevels() { + return List.of(); + } + + @Override + public ScriptManager getScriptManager() { + return getInstance(ScriptManager.KEY); + } + + @Override + public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() { + return null; + } + + @Override + public AsyncWaitStrategyFactory getAsyncWaitStrategyFactory() { + return null; + } + + @Override + public WatchManager getWatchManager() { + return getInstance(WatchManager.class); + } + + @Override + public NanoClock getNanoClock() { + return nanoClock; + } + + @Override + public void setNanoClock(final NanoClock nanoClock) { + // no-op + } + + @Override + public LoggerContext getLoggerContext() { + return loggerContextRef.get(); + } + + @Override + public void addFilter(final Filter filter) { + // no-op + } + + @Override + public void removeFilter(final Filter filter) { + // no-op + } + + @Override + public Filter getFilter() { + return filter; + } + + @Override + public boolean hasFilter() { + return true; + } + + @Override + public boolean isFiltered(final LogEvent event) { + // ignore all log events even if they somehow make it through + return true; + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullLoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullLoggerContext.java new file mode 100644 index 00000000000..93a0ba4b87d --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullLoggerContext.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config; + +import java.util.function.Supplier; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.message.FlowMessageFactory; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.util.PropertyResolver; + +public class NullLoggerContext extends LoggerContext { + public static final String NULL_NAME = "Null"; + + private NullLoggerContext(final Injector injector, final PropertyResolver propertyResolver, + final MessageFactory messageFactory, final FlowMessageFactory flowMessageFactory) { + super(NULL_NAME, NULL_NAME, null, null, injector, propertyResolver, + messageFactory, flowMessageFactory); + } + + public static NullLoggerContext getInstance() { + return new Builder().get(); + } + + private static class Builder extends GenericBuilder implements Supplier { + @Override + public NullLoggerContext get() { + return new NullLoggerContext(getInjector(), getPropertyResolver(), getMessageFactory(), getFlowMessageFactory()); + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java index 72e78b25eef..7658323941f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.config; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.lookup.InterpolatorFactory; import org.apache.logging.log4j.core.lookup.PropertiesLookup; @@ -24,10 +27,6 @@ import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import org.apache.logging.log4j.plugins.di.Key; - -import java.util.HashMap; -import java.util.Map; /** * Handles properties defined in the configuration. @@ -58,6 +57,6 @@ public static StrLookup configureSubstitutor(@PluginElement("Properties") final map.put(prop.getName(), prop.getValue()); } } - return config.getComponent(Key.forClass(InterpolatorFactory.class)).newInterpolator(new PropertiesLookup(map)); + return config.getInstance(InterpolatorFactory.class).newInterpolator(new PropertiesLookup(map)); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java index 957f107e2cc..17c156e0cd1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java @@ -17,20 +17,29 @@ package org.apache.logging.log4j.core.config; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Loader; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.spi.ClassFactory; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; /** * Factory for ReliabilityStrategies. */ +@ContextScoped public final class ReliabilityStrategyFactory { - private ReliabilityStrategyFactory() { + private final PropertyResolver propertyResolver; + private final ClassFactory classFactory; + + @Inject + public ReliabilityStrategyFactory(final PropertyResolver propertyResolver, final ClassFactory classFactory) { + this.propertyResolver = propertyResolver; + this.classFactory = classFactory; } /** * Returns a new {@code ReliabilityStrategy} instance based on the value of system property - * {@code log4j.ReliabilityStrategy}. If not value was specified this method returns a new + * {@value Log4jProperties#CONFIG_RELIABILITY_STRATEGY}. If not value was specified this method returns a new * {@code AwaitUnconditionallyReliabilityStrategy}. *

    * Valid values for this system property are {@code "AwaitUnconditionally"} (use @@ -44,10 +53,9 @@ private ReliabilityStrategyFactory() { * @return a ReliabilityStrategy that helps the specified LoggerConfig to log events reliably during or after a * configuration change */ - public static ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) { - - final String strategy = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.CONFIG_RELIABILITY_STRATEGY, - "AwaitCompletion"); + public ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) { + final String strategy = propertyResolver.getString(Log4jProperties.CONFIG_RELIABILITY_STRATEGY) + .orElse("AwaitCompletion"); if ("AwaitCompletion".equals(strategy)) { return new AwaitCompletionReliabilityStrategy(loggerConfig); } @@ -57,14 +65,17 @@ public static ReliabilityStrategy getReliabilityStrategy(final LoggerConfig logg if ("Locking".equals(strategy)) { return new LockingReliabilityStrategy(loggerConfig); } - try { - final Class cls = Loader.loadClass(strategy).asSubclass( - ReliabilityStrategy.class); - return cls.getConstructor(LoggerConfig.class).newInstance(loggerConfig); - } catch (final Exception dynamicFailed) { - StatusLogger.getLogger().warn( - "Could not create ReliabilityStrategy for '{}', using default AwaitCompletionReliabilityStrategy: {}", strategy, dynamicFailed); - return new AwaitCompletionReliabilityStrategy(loggerConfig); - } + return classFactory.tryGetClass(strategy, ReliabilityStrategy.class) + .map(clazz -> { + try { + return clazz.getConstructor(LoggerConfig.class).newInstance(loggerConfig); + } catch (final Exception dynamicFailed) { + StatusLogger.getLogger().warn( + "Could not create ReliabilityStrategy for '{}', using default AwaitCompletionReliabilityStrategy: {}", + strategy, dynamicFailed); + return null; + } + }) + .orElseGet(() -> new AwaitCompletionReliabilityStrategy(loggerConfig)); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java index 3cfc608249e..d4492840fa4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java @@ -87,7 +87,7 @@ public class DefaultConfigurationBuilder implement private long shutdownTimeoutMillis; private String advertiser; private LoggerContext loggerContext; - private String name; + private String name = "Constructed"; public static void formatXml(final Source source, final Result result) throws TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException { @@ -186,6 +186,9 @@ public T build(final boolean initialize) { if (source == null) { source = ConfigurationSource.NULL_SOURCE; } + if (loggerContext == null) { + loggerContext = LoggerContext.newBuilder().setName(name).get(); + } final Constructor constructor = clazz.getConstructor(LoggerContext.class, ConfigurationSource.class, Component.class); configuration = constructor.newInstance(loggerContext, source, root); configuration.getRootNode().getAttributes().putAll(root.getAttributes()); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java index 880a426e672..74354e6b5ab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java @@ -18,7 +18,6 @@ import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; @@ -29,7 +28,6 @@ import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.Reconfigurable; import org.apache.logging.log4j.core.config.status.StatusConfiguration; -import org.apache.logging.log4j.core.util.Patterns; import org.apache.logging.log4j.core.util.Source; import org.apache.logging.log4j.core.util.WatchManager; import org.apache.logging.log4j.core.util.Watcher; @@ -56,7 +54,7 @@ public CompositeConfiguration(final List config super(configurations.get(0).getLoggerContext(), ConfigurationSource.COMPOSITE_SOURCE); rootNode = configurations.get(0).getRootNode(); this.configurations = configurations; - mergeStrategy = getComponent(MergeStrategy.KEY); + mergeStrategy = getInstance(MergeStrategy.class); for (final AbstractConfiguration config : configurations) { mergeStrategy.mergeRootProperties(rootNode, config); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/jason/JsonConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/jason/JsonConfiguration.java index 18f1cf26042..a49b9ed2c59 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/jason/JsonConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/jason/JsonConfiguration.java @@ -32,12 +32,12 @@ import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.Reconfigurable; import org.apache.logging.log4j.core.config.status.StatusConfiguration; -import org.apache.logging.log4j.core.util.JsonReader; import org.apache.logging.log4j.core.util.Patterns; import org.apache.logging.log4j.plugins.Node; import org.apache.logging.log4j.plugins.model.PluginType; import org.apache.logging.log4j.plugins.util.ResolverUtil; import org.apache.logging.log4j.util.Cast; +import org.apache.logging.log4j.util.JsonReader; public class JsonConfiguration extends AbstractConfiguration implements Reconfigurable { private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() }; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java index c9e3d3ebb39..8ffc56b2289 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java @@ -25,6 +25,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.plugins.PluginElement; +import org.apache.logging.log4j.util.Cast; /** * Enhances a Class by allowing it to contain Filters. @@ -44,9 +45,8 @@ public abstract static class Builder> { @PluginElement("Properties") private Property[] propertyArray; - @SuppressWarnings("unchecked") public B asBuilder() { - return (B) this; + return Cast.cast(this); } public Filter getFilter() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java index efa7c1b9e67..91b414cf4c4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.plugins.Configurable; @@ -45,7 +45,7 @@ /** * Compares against a log level that is associated with a context value. By default the context is the - * {@link ThreadContext}, but users may {@linkplain ContextDataInjectorFactory configure} a custom + * {@link ThreadContext}, but users may {@linkplain ContextDataInjector configure} a custom * {@link ContextDataInjector} which obtains context data from some other source. */ @Configurable(elementType = Filter.ELEMENT_TYPE, printObject = true) @@ -53,30 +53,6 @@ @PerformanceSensitive("allocation") public final class DynamicThresholdFilter extends AbstractFilter { - /** - * Creates a DynamicThresholdFilter. - * @param key The name of the key to compare. - * @param pairs An array of value and Level pairs. - * @param defaultThreshold The default Level. - * @param onMatch The action to perform if a match occurs. - * @param onMismatch The action to perform if no match occurs. - * @return The DynamicThresholdFilter. - * @deprecated use {@link Builder} - */ - @Deprecated(since = "3.0.0", forRemoval = true) - public static DynamicThresholdFilter createFilter( - final String key, final KeyValuePair[] pairs, final Level defaultThreshold, final Result onMatch, - final Result onMismatch) { - return newBuilder() - .setKey(key) - .setPairs(pairs) - .setDefaultThreshold(defaultThreshold) - .setOnMatch(onMatch) - .setOnMismatch(onMismatch) - .setContextDataInjector(ContextDataInjectorFactory.createInjector()) - .get(); - } - @PluginFactory public static Builder newBuilder() { return new Builder(); @@ -87,6 +63,7 @@ public static class Builder extends AbstractFilter.AbstractFilterBuilder map = Stream.of(pairs).collect(Collectors.toMap(KeyValuePair::getKey, pair -> Level.toLevel(pair.getValue()))); - return new DynamicThresholdFilter(key, map, defaultThreshold, getOnMatch(), getOnMismatch(), contextDataInjector); + return new DynamicThresholdFilter(key, map, defaultThreshold, getOnMatch(), getOnMismatch(), contextDataInjector, contextDataFactory); } } private final Level defaultThreshold; private final String key; - private final ContextDataInjector injector; + private final ContextDataInjector contextDataInjector; private final Map levelMap; private DynamicThresholdFilter( final String key, final Map pairs, final Level defaultLevel, - final Result onMatch, final Result onMismatch, final ContextDataInjector injector) { + final Result onMatch, final Result onMismatch, + final ContextDataInjector contextDataInjector, final ContextDataFactory contextDataFactory) { super(onMatch, onMismatch); // ContextDataFactory looks up a property. The Spring PropertySource may log which will cause recursion. // By initializing the ContextDataFactory here recursion will be prevented. - StringMap map = ContextDataFactory.createContextData(); + StringMap map = contextDataFactory.createContextData(); LOGGER.debug("Successfully initialized ContextDataFactory by retrieving the context data with {} entries", map.size()); Objects.requireNonNull(key, "key cannot be null"); this.key = key; this.levelMap = pairs; this.defaultThreshold = defaultLevel; - this.injector = injector; + this.contextDataInjector = contextDataInjector; } @Override @@ -217,7 +202,7 @@ public Result filter(final Logger logger, final Level level, final Marker marker } private ReadOnlyStringMap currentContextData() { - return injector.rawContextData(); + return contextDataInjector.rawContextData(); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java index 7d7bf2f0f68..925d3ddf7a9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java @@ -28,29 +28,29 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationException; -import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationScheduler; import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.filter.mutable.KeyValuePairConfig; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; -import org.apache.logging.log4j.core.util.AuthorizationProvider; +import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.util.KeyValuePair; -import org.apache.logging.log4j.core.util.internal.HttpInputStreamUtil; +import org.apache.logging.log4j.core.util.internal.HttpResponse; +import org.apache.logging.log4j.core.util.internal.HttpSourceLoader; import org.apache.logging.log4j.core.util.internal.LastModifiedSource; import org.apache.logging.log4j.core.util.internal.Status; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginAliases; import org.apache.logging.log4j.plugins.PluginAttribute; import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.util.PerformanceSensitive; -import org.apache.logging.log4j.util.PropertiesUtil; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -72,19 +72,29 @@ public class MutableThreadContextMapFilter extends AbstractFilter { private final long pollInterval; private final ConfigurationScheduler scheduler; private final LastModifiedSource source; - private final AuthorizationProvider authorizationProvider; private final List listeners = new ArrayList<>(); private ScheduledFuture future = null; - - private MutableThreadContextMapFilter(final Filter filter, final LastModifiedSource source, - final long pollInterval, final AuthorizationProvider authorizationProvider, - final Result onMatch, final Result onMismatch, final Configuration configuration) { + private final ContextDataInjector contextDataInjector; + private final ContextDataFactory contextDataFactory; + private final HttpSourceLoader httpSourceLoader; + + private MutableThreadContextMapFilter(final Filter filter, + final LastModifiedSource source, + final long pollInterval, + final Result onMatch, + final Result onMismatch, + final Configuration configuration, + final ContextDataInjector contextDataInjector, + final ContextDataFactory contextDataFactory, + final HttpSourceLoader httpSourceLoader) { super(onMatch, onMismatch); this.filter = filter; this.pollInterval = pollInterval; this.source = source; this.scheduler = configuration.getScheduler(); - this.authorizationProvider = authorizationProvider; + this.contextDataInjector = contextDataInjector; + this.contextDataFactory = contextDataFactory; + this.httpSourceLoader = httpSourceLoader; } @Override @@ -210,6 +220,14 @@ public static class Builder extends AbstractFilterBuilder @PluginConfiguration private Configuration configuration; + private ContextDataInjector contextDataInjector; + + private ContextDataFactory contextDataFactory; + + // HttpSourceLoader is not exported, so let's keep it hidden + @Inject + private HttpSourceLoader httpSourceLoader; + /** * Sets the Configuration. * @param configuration The Configuration. @@ -241,29 +259,45 @@ public Builder setConfigLocation(final String configLocation) { return this; } + @Inject + public Builder setContextDataInjector(final ContextDataInjector contextDataInjector) { + this.contextDataInjector = contextDataInjector; + return this; + } + + @Inject + public Builder setContextDataFactory(final ContextDataFactory contextDataFactory) { + this.contextDataFactory = contextDataFactory; + return this; + } + @Override public MutableThreadContextMapFilter build() { final LastModifiedSource source = getSource(configLocation); if (source == null) { return new MutableThreadContextMapFilter(new NoOpFilter(), null, 0, - null, getOnMatch(), getOnMismatch(), configuration); + getOnMatch(), getOnMismatch(), configuration, contextDataInjector, contextDataFactory, httpSourceLoader); } - final AuthorizationProvider authorizationProvider = - ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties()); Filter filter; if (pollInterval <= 0) { - ConfigResult result = getConfig(source, authorizationProvider); - if (result.status == Status.SUCCESS) { + ConfigResult result = getConfig(source, httpSourceLoader); + if (result.getStatus() == Status.SUCCESS) { if (result.pairs.length > 0) { - filter = ThreadContextMapFilter.createFilter(result.pairs, "or", - getOnMatch(), getOnMismatch()); + filter = ThreadContextMapFilter.newBuilder() + .setPairs(result.pairs) + .setOperator("or") + .setOnMatch(getOnMatch()) + .setOnMismatch(getOnMismatch()) + .setContextDataInjector(contextDataInjector) + .setContextDataFactory(contextDataFactory) + .get(); } else { filter = new NoOpFilter(); } - } else if (result.status == Status.NOT_FOUND || result.status == Status.EMPTY) { + } else if (result.getStatus() == Status.NOT_FOUND || result.getStatus() == Status.EMPTY) { filter = new NoOpFilter(); } else { - LOGGER.warn("Unexpected response returned on initial call: {}", result.status); + LOGGER.warn("Unexpected response returned on initial call: {}", result.getStatus()); filter = new NoOpFilter(); } } else { @@ -273,8 +307,8 @@ public MutableThreadContextMapFilter build() { if (pollInterval > 0) { configuration.getScheduler().incrementScheduledItems(); } - return new MutableThreadContextMapFilter(filter, source, pollInterval, authorizationProvider, - getOnMatch(), getOnMismatch(), configuration); + return new MutableThreadContextMapFilter(filter, source, pollInterval, getOnMatch(), getOnMismatch(), + configuration, contextDataInjector, contextDataFactory, httpSourceLoader); } } @@ -282,20 +316,21 @@ private class FileMonitor implements Runnable { @Override public void run() { - final ConfigResult result = getConfig(source, authorizationProvider); - if (result.status == Status.SUCCESS) { + final ConfigResult result = getConfig(source, httpSourceLoader); + if (result.getStatus() == Status.SUCCESS) { filter = ThreadContextMapFilter.newBuilder() .setPairs(result.pairs) .setOperator("or") .setOnMatch(getOnMatch()) .setOnMismatch(getOnMismatch()) - .setContextDataInjector(ContextDataInjectorFactory.createInjector()) + .setContextDataInjector(contextDataInjector) + .setContextDataFactory(contextDataFactory) .get(); LOGGER.info("Filter configuration was updated: {}", filter.toString()); for (FilterConfigUpdateListener listener : listeners) { listener.onEvent(); } - } else if (result.status == Status.NOT_FOUND) { + } else if (result.getStatus() == Status.NOT_FOUND) { if (!(filter instanceof NoOpFilter)) { LOGGER.info("Filter configuration was removed"); filter = new NoOpFilter(); @@ -303,7 +338,7 @@ public void run() { listener.onEvent(); } } - } else if (result.status == Status.EMPTY) { + } else if (result.getStatus() == Status.EMPTY) { LOGGER.debug("Filter configuration is empty"); filter = new NoOpFilter(); } @@ -327,10 +362,10 @@ private static LastModifiedSource getSource(final String configLocation) { } private static ConfigResult getConfig(final LastModifiedSource source, - final AuthorizationProvider authorizationProvider) { + final HttpSourceLoader httpSourceLoader) { final File inputFile = source.getFile(); InputStream inputStream = null; - HttpInputStreamUtil.Result result = null; + HttpResponse response; final long lastModified = source.getLastModified(); if (inputFile != null && inputFile.exists()) { try { @@ -338,25 +373,24 @@ private static ConfigResult getConfig(final LastModifiedSource source, if (modified > lastModified) { source.setLastModified(modified); inputStream = new FileInputStream(inputFile); - result = new HttpInputStreamUtil.Result(Status.SUCCESS); + response = new HttpResponse(Status.SUCCESS); } else { - result = new HttpInputStreamUtil.Result(Status.NOT_MODIFIED); + response = new HttpResponse(Status.NOT_MODIFIED); } } catch (Exception ex) { - result = new HttpInputStreamUtil.Result(Status.ERROR); + response = new HttpResponse(Status.ERROR); } } else if (source.getURI() != null) { try { - result = HttpInputStreamUtil.getInputStream(source, authorizationProvider); - inputStream = result.getInputStream(); + response = httpSourceLoader.load(source); + inputStream = response.getInputStream(); } catch (ConfigurationException ex) { - result = new HttpInputStreamUtil.Result(Status.ERROR); + response = new HttpResponse(Status.ERROR); } } else { - result = new HttpInputStreamUtil.Result(Status.NOT_FOUND); + response = new HttpResponse(Status.NOT_FOUND); } - final ConfigResult configResult = new ConfigResult(); - if (result.getStatus() == Status.SUCCESS) { + if (response.getStatus() == Status.SUCCESS) { LOGGER.debug("Processing Debug key/value pairs from: {}", source.toString()); try { final KeyValuePairConfig keyValuePairConfig = MAPPER.readValue(inputStream, KeyValuePairConfig.class); @@ -375,27 +409,21 @@ private static ConfigResult getConfig(final LastModifiedSource source, } } if (pairs.size() > 0) { - configResult.pairs = pairs.toArray(EMPTY_ARRAY); - configResult.status = Status.SUCCESS; - } else { - configResult.status = Status.EMPTY; + return new ConfigResult(Status.SUCCESS, pairs.toArray(EMPTY_ARRAY)); } - } else { - LOGGER.debug("No configuration data in {}", source.toString()); - configResult.status = Status.EMPTY; + return new ConfigResult(Status.EMPTY); } - } else { - LOGGER.warn("No configs element in MutableThreadContextMapFilter configuration"); - configResult.status = Status.ERROR; + LOGGER.debug("No configuration data in {}", source.toString()); + return new ConfigResult(Status.EMPTY); } + LOGGER.warn("No configs element in MutableThreadContextMapFilter configuration"); + return new ConfigResult(Status.ERROR); } catch (Exception ex) { LOGGER.warn("Invalid key/value pair configuration, input ignored: {}", ex.getMessage()); - configResult.status = Status.ERROR; + return new ConfigResult(Status.ERROR); } - } else { - configResult.status = result.getStatus(); } - return configResult; + return new ConfigResult(Status.ERROR); } private static class NoOpFilter extends AbstractFilter { @@ -409,8 +437,17 @@ public interface FilterConfigUpdateListener { void onEvent(); } - private static class ConfigResult extends HttpInputStreamUtil.Result { - public KeyValuePair[] pairs; - public Status status; + private static class ConfigResult extends HttpResponse { + private final KeyValuePair[] pairs; + + private ConfigResult(final Status status) { + super(status); + this.pairs = EMPTY_ARRAY; + } + + private ConfigResult(final Status status, final KeyValuePair... pairs) { + super(status); + this.pairs = pairs; + } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java index 37919806958..58c68107f05 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java @@ -30,7 +30,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.plugins.Configurable; @@ -55,19 +56,19 @@ @PerformanceSensitive("allocation") public class ThreadContextMapFilter extends MapFilter { - private final ContextDataInjector injector; + private final ContextDataInjector contextDataInjector; private final String key; private final String value; private final boolean useMap; public ThreadContextMapFilter( - final Map> pairs, final boolean oper, final Result onMatch, - final Result onMismatch, final ContextDataInjector injector) { + final Map> pairs, final boolean oper, final Result onMatch, final Result onMismatch, + final ContextDataInjector contextDataInjector, final ContextDataFactory contextDataFactory) { super(pairs, oper, onMatch, onMismatch); // ContextDataFactory looks up a property. The Spring PropertySource may log which will cause recursion. // By initializing the ContextDataFactory here recursion will be prevented. - StringMap map = ContextDataFactory.createContextData(); + StringMap map = contextDataFactory.createContextData(); LOGGER.debug("Successfully initialized ContextDataFactory by retrieving the context data with {} entries", map.size()); if (pairs.size() == 1) { @@ -87,7 +88,7 @@ public ThreadContextMapFilter( this.value = null; this.useMap = true; } - this.injector = injector; + this.contextDataInjector = contextDataInjector; } @Override @@ -130,7 +131,7 @@ private Result filter() { } private ReadOnlyStringMap currentContextData() { - return injector.rawContextData(); + return contextDataInjector.rawContextData(); } @Override @@ -211,6 +212,7 @@ public static class Builder extends AbstractFilterBuilder implements Su private KeyValuePair[] pairs; private String operator; private ContextDataInjector contextDataInjector; + private ContextDataFactory contextDataFactory; public Builder setPairs(@Required @PluginElement final KeyValuePair[] pairs) { this.pairs = pairs; @@ -228,12 +230,24 @@ public Builder setContextDataInjector(final ContextDataInjector contextDataInjec return this; } + @Inject + public Builder setContextDataFactory(final ContextDataFactory contextDataFactory) { + this.contextDataFactory = contextDataFactory; + return this; + } + @Override public ThreadContextMapFilter get() { if (pairs == null || pairs.length == 0) { LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter"); return null; } + if (contextDataFactory == null) { + contextDataFactory = new DefaultContextDataFactory(); + } + if (contextDataInjector == null) { + contextDataInjector = ThreadContextDataInjector.create(contextDataFactory); + } final Map> map = new HashMap<>(); for (final KeyValuePair pair : pairs) { final String key = pair.getKey(); @@ -260,7 +274,8 @@ public ThreadContextMapFilter get() { return null; } final boolean isAnd = operator == null || !operator.equalsIgnoreCase("or"); - return new ThreadContextMapFilter(map, isAnd, getOnMatch(), getOnMismatch(), contextDataInjector); + return new ThreadContextMapFilter(map, isAnd, getOnMatch(), getOnMismatch(), + contextDataInjector, contextDataFactory); } } @@ -269,15 +284,4 @@ public static Builder newBuilder() { return new Builder(); } - @Deprecated(since = "3.0.0", forRemoval = true) - public static ThreadContextMapFilter createFilter( - final KeyValuePair[] pairs, final String operator, final Result onMatch, final Result onMismatch) { - return newBuilder() - .setPairs(pairs) - .setOperator(operator) - .setOnMatch(onMatch) - .setOnMismatch(onMismatch) - .setContextDataInjector(ContextDataInjectorFactory.createInjector()) - .get(); - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java index c321724abc2..19b58a406ea 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java @@ -23,6 +23,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.Objects; import java.util.function.Supplier; import org.apache.logging.log4j.Level; @@ -31,7 +32,6 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.time.Clock; -import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Inject; @@ -87,6 +87,7 @@ public final class TimeFilter extends AbstractFilter { this.startTime = start; this.endTime = end; this.timeZone = timeZone; + this.clock = Objects.requireNonNull(clock); this.start = ZonedDateTime.of(now, startTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli(); long endMillis = ZonedDateTime.of(now, endTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli(); if (end.isBefore(start)) { @@ -101,7 +102,6 @@ public final class TimeFilter extends AbstractFilter { endMillis -= difference; } this.end = endMillis; - this.clock = clock; } private TimeFilter( @@ -243,33 +243,6 @@ public String toString() { return sb.toString(); } - /** - * Creates a TimeFilter. - * @param start The start time. - * @param end The end time. - * @param tz timezone. - * @param match Action to perform if the time matches. - * @param mismatch Action to perform if the action does not match. - * @return A TimeFilter. - */ - @Deprecated(since = "3.0.0", forRemoval = true) - public static TimeFilter createFilter( - final String start, final String end, final String tz, final Result match, final Result mismatch) { - final Builder builder = newBuilder() - .setStart(start) - .setEnd(end); - if (tz != null) { - builder.setTimezone(ZoneId.of(tz)); - } - if (match != null) { - builder.setOnMatch(match); - } - if (mismatch != null) { - builder.setOnMismatch(mismatch); - } - return builder.get(); - } - private static LocalTime parseTimestamp(final String timestamp, final LocalTime defaultValue) { if (timestamp == null) { return defaultValue; @@ -320,9 +293,6 @@ public Builder setClock(final Clock clock) { public TimeFilter get() { final LocalTime startTime = parseTimestamp(start, LocalTime.MIN); final LocalTime endTime = parseTimestamp(end, LocalTime.MAX); - if (clock == null) { - clock = ClockFactory.getClock(); - } return new TimeFilter(startTime, endTime, timezone, getOnMatch(), getOnMismatch(), clock); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java index 5676672ca86..b576f88d3a7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java @@ -16,131 +16,29 @@ */ package org.apache.logging.log4j.core.impl; -import java.lang.reflect.Constructor; import java.util.Map; -import java.util.Map.Entry; -import org.apache.logging.log4j.core.ContextDataInjector; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.util.Loader; -import org.apache.logging.log4j.util.IndexedStringMap; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; -/** - * Factory for creating the StringMap instances used to initialize LogEvents' {@linkplain LogEvent#getContextData() - * context data}. When context data is {@linkplain ContextDataInjector injected} into the log event, these StringMap - * instances may be either populated with key-value pairs from the context, or completely replaced altogether. - *

    - * By default returns {@code SortedArrayStringMap} objects. Can be configured by setting system property - * {@value Log4jProperties#THREAD_CONTEXT_DATA_CLASS_NAME} - * to the fully qualified class name of a class implementing the {@code StringMap} - * interface. The class must have a public default constructor, and if possible should also have a public constructor - * that takes a single {@code int} argument for the initial capacity. - *

    - * - * @see LogEvent#getContextData() - * @see ContextDataInjector - * @see SortedArrayStringMap - * @since 2.7 - */ -public class ContextDataFactory { - private static final String CLASS_NAME = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.THREAD_CONTEXT_DATA_CLASS_NAME); - private static final Class CACHED_CLASS = createCachedClass(CLASS_NAME); - - /** - * In LOG4J2-2649 (https://issues.apache.org/jira/browse/LOG4J2-2649), - * the reporter said some reason about using graalvm to static compile. - * In graalvm doc (https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md), - * graalvm is not support MethodHandle now, so the Constructor need not to return MethodHandle. - */ - private static final Constructor DEFAULT_CONSTRUCTOR = createDefaultConstructor(CACHED_CLASS); - private static final Constructor INITIAL_CAPACITY_CONSTRUCTOR = createInitialCapacityConstructor(CACHED_CLASS); - - private static final StringMap EMPTY_STRING_MAP = createContextData(0); - - static { - EMPTY_STRING_MAP.freeze(); - } - - private static Class createCachedClass(final String className) { - if (className == null) { - return null; - } - try { - return Loader.loadClass(className).asSubclass(IndexedStringMap.class); - } catch (final Exception any) { - return null; - } - } +public interface ContextDataFactory { + StringMap createContextData(); - private static Constructor createDefaultConstructor(final Class cachedClass){ - if (cachedClass == null) { - return null; - } - try { - return cachedClass.getConstructor(); - } catch (final NoSuchMethodException | IllegalAccessError ignored) { - return null; - } - } + StringMap createContextData(final int initialCapacity); - private static Constructor createInitialCapacityConstructor(final Class cachedClass){ - if (cachedClass == null) { - return null; - } - try { - return cachedClass.getConstructor(int.class); - } catch (final NoSuchMethodException | IllegalAccessError ignored) { - return null; - } - } - - public static StringMap createContextData() { - if (DEFAULT_CONSTRUCTOR == null) { - return new SortedArrayStringMap(); - } - try { - return (IndexedStringMap) DEFAULT_CONSTRUCTOR.newInstance(); - } catch (final Throwable ignored) { - return new SortedArrayStringMap(); - } - } - - public static StringMap createContextData(final int initialCapacity) { - if (INITIAL_CAPACITY_CONSTRUCTOR == null) { - return new SortedArrayStringMap(initialCapacity); - } - try { - return (IndexedStringMap) INITIAL_CAPACITY_CONSTRUCTOR.newInstance(initialCapacity); - } catch (final Throwable ignored) { - return new SortedArrayStringMap(initialCapacity); - } - } - - public static StringMap createContextData(final Map context) { + default StringMap createContextData(final Map context) { final StringMap contextData = createContextData(context.size()); - for (final Entry entry : context.entrySet()) { + for (final Map.Entry entry : context.entrySet()) { contextData.putValue(entry.getKey(), entry.getValue()); } return contextData; } - public static StringMap createContextData(final ReadOnlyStringMap readOnlyStringMap) { + default StringMap createContextData(final ReadOnlyStringMap readOnlyStringMap) { final StringMap contextData = createContextData(readOnlyStringMap.size()); contextData.putAll(readOnlyStringMap); return contextData; } - /** - * An empty pre-frozen IndexedStringMap. The returned object may be shared. - * - * @return an empty pre-frozen IndexedStringMap - */ - public static StringMap emptyFrozenContextData() { - return EMPTY_STRING_MAP; - } - + StringMap emptyFrozenContextData(); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java deleted file mode 100644 index 2ff65023b6b..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.ContextDataInjector; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.util.Loader; -import org.apache.logging.log4j.spi.CopyOnWrite; -import org.apache.logging.log4j.spi.DefaultThreadContextMap; -import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; -import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.ReadOnlyStringMap; - -/** - * Factory for ContextDataInjectors. Returns a new {@code ContextDataInjector} instance based on the value of system - * property {@code log4j2.ContextDataInjector}. Users may use this system property to specify the fully qualified class - * name of a class that implements the {@code ContextDataInjector} interface. - * If no value was specified this factory method returns one of the injectors defined in - * {@code ThreadContextDataInjector}. - * - * @see ContextDataInjector - * @see ReadOnlyStringMap - * @see ThreadContextDataInjector - * @see LogEvent#getContextData() - * @since 2.7 - */ -public class ContextDataInjectorFactory { - - /** - * Returns a new {@code ContextDataInjector} instance based on the value of system property - * {@code log4j2.ContextDataInjector}. If no value was specified this factory method returns one of the - * {@code ContextDataInjector} classes defined in {@link ThreadContextDataInjector} which is most appropriate for - * the ThreadContext implementation. - *

    - * Note: It is no longer recommended that users provide a custom implementation of the ContextDataInjector. - * Instead, provide a {@code ContextDataProvider}. - *

    - *

    - * Users may use this system property to specify the fully qualified class name of a class that implements the - * {@code ContextDataInjector} interface. - *

    - * When providing a custom {@code ContextDataInjector}, be aware that this method may be invoked multiple times by - * the various components in Log4j that need access to context data. - * This includes the object(s) that populate log events, but also various lookups and filters that look at - * context data to determine whether an event should be logged. - *

    - * - * @return a ContextDataInjector that populates the {@code ReadOnlyStringMap} of all {@code LogEvent} objects - * @see LogEvent#getContextData() - * @see ContextDataInjector - */ - public static ContextDataInjector createInjector() { - final String className = PropertiesUtil.getProperties().getStringProperty(Log4jProperties.THREAD_CONTEXT_DATA_INJECTOR_CLASS_NAME); - if (className == null) { - return createDefaultInjector(); - } - try { - final Class cls = Loader.loadClass(className).asSubclass( - ContextDataInjector.class); - return cls.newInstance(); - } catch (final Exception dynamicFailed) { - final ContextDataInjector result = createDefaultInjector(); - StatusLogger.getLogger().warn( - "Could not create ContextDataInjector for '{}', using default {}: {}", - className, result.getClass().getName(), dynamicFailed); - return result; - } - } - - private static ContextDataInjector createDefaultInjector() { - final ReadOnlyThreadContextMap threadContextMap = ThreadContext.getThreadContextMap(); - - // note: map may be null (if legacy custom ThreadContextMap was installed by user) - if (threadContextMap instanceof DefaultThreadContextMap || threadContextMap == null) { - return new ThreadContextDataInjector.ForDefaultThreadContextMap(); // for non StringMap-based context maps - } - if (threadContextMap instanceof CopyOnWrite) { - return new ThreadContextDataInjector.ForCopyOnWriteThreadContextMap(); - } - return new ThreadContextDataInjector.ForGarbageFreeThreadContextMap(); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java index 6e5f4f8168c..a26c82d7dba 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java @@ -16,20 +16,18 @@ */ package org.apache.logging.log4j.core.impl; -import java.util.Map; -import java.util.function.Supplier; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.async.AsyncQueueFullPolicy; +import org.apache.logging.log4j.core.async.AsyncQueueFullPolicyFactory; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfigurationFactory; +import org.apache.logging.log4j.core.config.DefaultLoggerContextNamingStrategy; +import org.apache.logging.log4j.core.config.LoggerContextNamingStrategy; import org.apache.logging.log4j.core.config.composite.DefaultMergeStrategy; import org.apache.logging.log4j.core.config.composite.MergeStrategy; -import org.apache.logging.log4j.core.lookup.Interpolator; import org.apache.logging.log4j.core.lookup.InterpolatorFactory; -import org.apache.logging.log4j.core.lookup.StrLookup; import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; import org.apache.logging.log4j.core.selector.ContextSelector; @@ -41,51 +39,63 @@ import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.time.internal.SystemClock; import org.apache.logging.log4j.core.time.internal.SystemMillisClock; +import org.apache.logging.log4j.core.util.AuthorizationProvider; +import org.apache.logging.log4j.core.util.BasicAuthorizationProvider; import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry; import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; import org.apache.logging.log4j.plugins.Factory; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Named; -import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.SingletonFactory; import org.apache.logging.log4j.plugins.condition.ConditionalOnProperty; import org.apache.logging.log4j.plugins.di.InjectException; import org.apache.logging.log4j.plugins.di.Injector; -import org.apache.logging.log4j.spi.CopyOnWrite; -import org.apache.logging.log4j.spi.DefaultThreadContextMap; -import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; +import org.apache.logging.log4j.spi.ClassFactory; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.RecyclerFactories; +import org.apache.logging.log4j.util.RecyclerFactory; import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled; /** - * Contains default bindings for Log4j including support for {@link PropertiesUtil}-based configuration. + * Contains default bindings for Log4j. * * @see Log4jProperties * @see ContextSelector * @see ShutdownCallbackRegistry * @see Clock * @see NanoClock - * @see ConfigurationFactory * @see MergeStrategy - * @see InterpolatorFactory * @see ContextDataInjector + * @see ContextDataFactory * @see LogEventFactory * @see StrSubstitutor + * @see AsyncQueueFullPolicy + * @see AuthorizationProvider + * @see RecyclerFactory + * @see RecyclerFactories + * @see ConfigurationFactory */ public class DefaultBundle { private static final Logger LOGGER = StatusLogger.getLogger(); private final Injector injector; - private final PropertyEnvironment properties; - private final ClassLoader classLoader; + private final PropertyResolver propertyResolver; + private final ClassFactory classFactory; - public DefaultBundle(final Injector injector, final PropertyEnvironment properties, final ClassLoader classLoader) { + @Inject + public DefaultBundle(final Injector injector, final PropertyResolver propertyResolver, final ClassFactory classFactory) { this.injector = injector; - this.properties = properties; - this.classLoader = classLoader; + this.propertyResolver = propertyResolver; + this.classFactory = classFactory; + } + + @SingletonFactory + @Ordered(Integer.MIN_VALUE) + public LoggerContextNamingStrategy defaultLoggerContextNamingStrategy() { + return new DefaultLoggerContextNamingStrategy(); } @ConditionalOnProperty(name = Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME) @@ -95,9 +105,10 @@ public ContextSelector systemPropertyContextSelector() throws ClassNotFoundExcep return newInstanceOfProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, ContextSelector.class); } - @SingletonFactory - public ContextSelector defaultContextSelector() { - return new ClassLoaderContextSelector(injector); + @Factory + @Ordered(Integer.MIN_VALUE) + public ContextSelector defaultContextSelector(final ClassLoaderContextSelector contextSelector) { + return contextSelector; } @ConditionalOnProperty(name = Log4jProperties.SHUTDOWN_CALLBACK_REGISTRY_CLASS_NAME) @@ -107,157 +118,150 @@ public ShutdownCallbackRegistry systemPropertyShutdownCallbackRegistry() throws return newInstanceOfProperty(Log4jProperties.SHUTDOWN_CALLBACK_REGISTRY_CLASS_NAME, ShutdownCallbackRegistry.class); } - @SingletonFactory - public ShutdownCallbackRegistry defaultShutdownCallbackRegistry() { - return new DefaultShutdownCallbackRegistry(); + @Factory + @Ordered(Integer.MIN_VALUE) + public ShutdownCallbackRegistry defaultShutdownCallbackRegistry(final DefaultShutdownCallbackRegistry registry) { + return registry; } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "SystemClock") - @SingletonFactory + @Factory @Ordered(200) public Clock systemClock() { return logSupportedPrecision(new SystemClock()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "SystemMillisClock") - @SingletonFactory + @Factory @Ordered(200) public Clock systemMillisClock() { return logSupportedPrecision(new SystemMillisClock()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "CachedClock") - @SingletonFactory + @Factory @Ordered(200) public Clock cachedClock() { return logSupportedPrecision(CachedClock.instance()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "org.apache.logging.log4j.core.time.internal.CachedClock") - @SingletonFactory + @Factory @Ordered(200) public Clock cachedClockFqcn() { return logSupportedPrecision(CachedClock.instance()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "CoarseCachedClock") - @SingletonFactory + @Factory @Ordered(200) public Clock coarseCachedClock() { return logSupportedPrecision(CoarseCachedClock.instance()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK, value = "org.apache.logging.log4j.core.time.internal.CoarseCachedClock") - @SingletonFactory + @Factory @Ordered(200) public Clock coarseCachedClockFqcn() { return logSupportedPrecision(CoarseCachedClock.instance()); } @ConditionalOnProperty(name = Log4jProperties.CONFIG_CLOCK) - @SingletonFactory + @Factory @Ordered(100) public Clock systemPropertyClock() throws ClassNotFoundException { return logSupportedPrecision(newInstanceOfProperty(Log4jProperties.CONFIG_CLOCK, Clock.class)); } - @SingletonFactory + @Factory + @Ordered(Integer.MIN_VALUE) public Clock defaultClock() { return new SystemClock(); } - @SingletonFactory + @Factory + @Ordered(Integer.MIN_VALUE) public NanoClock defaultNanoClock() { return new DummyNanoClock(); } - @ConditionalOnProperty(name = Log4jProperties.THREAD_CONTEXT_DATA_INJECTOR_CLASS_NAME) - @Factory + @ConditionalOnProperty(name = Log4jProperties.STATUS_DEFAULT_LEVEL) + @SingletonFactory + @Named("StatusLogger") @Ordered(100) - public ContextDataInjector systemPropertyContextDataInjector() throws ClassNotFoundException { - return newInstanceOfProperty(Log4jProperties.THREAD_CONTEXT_DATA_INJECTOR_CLASS_NAME, ContextDataInjector.class); + public Level systemPropertyDefaultStatusLevel() { + return propertyResolver.getString(Log4jProperties.STATUS_DEFAULT_LEVEL).map(Level::getLevel).orElse(Level.ERROR); } - @Factory - public ContextDataInjector defaultContextDataInjector() { - final ReadOnlyThreadContextMap threadContextMap = ThreadContext.getThreadContextMap(); - - // note: map may be null (if legacy custom ThreadContextMap was installed by user) - if (threadContextMap instanceof DefaultThreadContextMap || threadContextMap == null) { - // for non StringMap-based context maps - return new ThreadContextDataInjector.ForDefaultThreadContextMap(); - } - if (threadContextMap instanceof CopyOnWrite) { - return new ThreadContextDataInjector.ForCopyOnWriteThreadContextMap(); - } - return new ThreadContextDataInjector.ForGarbageFreeThreadContextMap(); + @SingletonFactory + @Named("StatusLogger") + @Ordered(Integer.MIN_VALUE) + public Level defaultStatusLevel() { + return Level.ERROR; } - @ConditionalOnProperty(name = Log4jProperties.LOG_EVENT_FACTORY_CLASS_NAME) - @SingletonFactory - @Ordered(100) - public LogEventFactory systemPropertyLogEventFactory() throws ClassNotFoundException { - return newInstanceOfProperty(Log4jProperties.LOG_EVENT_FACTORY_CLASS_NAME, LogEventFactory.class); + @Factory + @Ordered(Integer.MIN_VALUE) + public MergeStrategy defaultMergeStrategy(final DefaultMergeStrategy strategy) { + return strategy; } - @SingletonFactory - public LogEventFactory defaultLogEventFactory( - final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock) { - return isThreadLocalsEnabled() ? new ReusableLogEventFactory(injector, clock, nanoClock) : - new DefaultLogEventFactory(injector, clock, nanoClock); + @Factory + @Ordered(Integer.MIN_VALUE) + public ContextDataFactory defaultContextDataFactory() { + return new DefaultContextDataFactory(); } - @SingletonFactory - public InterpolatorFactory interpolatorFactory( - @Namespace(StrLookup.CATEGORY) final Map> strLookupPlugins) { - return defaultLookup -> new Interpolator(defaultLookup, strLookupPlugins); + @Factory + @Ordered(Integer.MIN_VALUE) + public ContextDataInjector defaultContextDataInjector(final ContextDataFactory factory) { + return ThreadContextDataInjector.create(factory); } - @SingletonFactory - public StrSubstitutor strSubstitutor(final InterpolatorFactory factory) { - return new StrSubstitutor(factory.newInterpolator(null)); + @Factory + @Ordered(Integer.MIN_VALUE) + public LogEventFactory defaultLogEventFactory(final Injector injector, final PropertyResolver resolver) { + final Class factoryClass = isThreadLocalsEnabled(resolver) + ? ReusableLogEventFactory.class + : DefaultLogEventFactory.class; + return injector.getInstance(factoryClass); } - @SingletonFactory - public ConfigurationFactory configurationFactory(final StrSubstitutor substitutor) { - // TODO(ms): should be able to @Import classes to get @ConditionalOnWhatever on the classes to treat as bundles-ish? - final DefaultConfigurationFactory factory = new DefaultConfigurationFactory(injector); - factory.setSubstitutor(substitutor); - return factory; + @Factory + @Ordered(Integer.MIN_VALUE) + public AsyncQueueFullPolicy defaultAsyncQueueFullPolicy(final AsyncQueueFullPolicyFactory factory) { + return factory.get(); } - @ConditionalOnProperty(name = Log4jProperties.CONFIG_MERGE_STRATEGY_CLASS_NAME) - @SingletonFactory - @Ordered(100) - public MergeStrategy systemPropertyMergeStrategy() throws ClassNotFoundException { - return newInstanceOfProperty(Log4jProperties.CONFIG_MERGE_STRATEGY_CLASS_NAME, MergeStrategy.class); + @Factory + @Ordered(Integer.MIN_VALUE) + public AuthorizationProvider defaultAuthorizationProvider(final BasicAuthorizationProvider provider) { + return provider; } - @SingletonFactory - public MergeStrategy defaultMergeStrategy() { - return new DefaultMergeStrategy(); + @Factory + @Ordered(Integer.MIN_VALUE) + public StrSubstitutor defaultStrSubstitutor(final InterpolatorFactory factory) { + return new StrSubstitutor(factory.newInterpolator(null)); } - @ConditionalOnProperty(name = Log4jProperties.STATUS_DEFAULT_LEVEL) - @SingletonFactory - @Named("StatusLogger") - @Ordered(100) - public Level systemPropertyDefaultStatusLevel() { - return Level.getLevel(properties.getStringProperty(Log4jProperties.STATUS_DEFAULT_LEVEL)); + @Factory + @Ordered(Integer.MIN_VALUE) + public RecyclerFactory defaultRecyclerFactory() { + return RecyclerFactories.ofSpec(null); } - @SingletonFactory - @Named("StatusLogger") - public Level defaultStatusLevel() { - return Level.ERROR; + @Factory + @Ordered(Integer.MIN_VALUE) + public ConfigurationFactory defaultConfigurationFactory(final DefaultConfigurationFactory factory) { + return factory; } private T newInstanceOfProperty(final String propertyName, final Class supertype) throws ClassNotFoundException { - final String property = properties.getStringProperty(propertyName); - if (property == null) { - throw new InjectException("No property defined for name " + propertyName); - } - return injector.getInstance(classLoader.loadClass(property).asSubclass(supertype)); + final String property = propertyResolver.getString(propertyName) + .orElseThrow(() -> new InjectException("No property defined for name " + propertyName)); + final Class clazz = classFactory.getClass(property, supertype); + return injector.getInstance(clazz); } private static Clock logSupportedPrecision(final Clock clock) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java index df5912ca12e..a4e03407ec7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java @@ -16,16 +16,25 @@ */ package org.apache.logging.log4j.core.impl; -import org.apache.logging.log4j.core.util.Loader; +import java.security.AccessController; +import java.security.PrivilegedAction; + import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.plugins.di.InjectorCallback; -import org.apache.logging.log4j.util.PropertiesUtil; public class DefaultCallback implements InjectorCallback { @Override public void configure(final Injector injector) { - injector.setReflectionAccessor(object -> object.setAccessible(true)); - injector.registerBundle(new DefaultBundle(injector, PropertiesUtil.getProperties(), Loader.getClassLoader())); + if (System.getSecurityManager() != null) { + injector.setReflectionAccessor(object -> AccessController.doPrivileged((PrivilegedAction) () -> { + object.setAccessible(true); + return null; + })); + + } else { + injector.setReflectionAccessor(object -> object.setAccessible(true)); + } + injector.registerBundle(DefaultBundle.class); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultContextDataFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultContextDataFactory.java new file mode 100644 index 00000000000..b1b75a21cd8 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultContextDataFactory.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.impl; + +import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.util.SortedArrayStringMap; +import org.apache.logging.log4j.util.StringMap; + +/** + * Factory for creating the StringMap instances used to initialize LogEvents' {@linkplain LogEvent#getContextData() + * context data}. When context data is {@linkplain ContextDataInjector injected} into the log event, these StringMap + * instances may be either populated with key-value pairs from the context, or completely replaced altogether. + *

    + * By default returns {@code SortedArrayStringMap} objects. Can be configured by registering a custom binding for + * {@link ContextDataFactory}. + *

    + * + * @see LogEvent#getContextData() + * @see ContextDataInjector + * @see SortedArrayStringMap + * @since 3.0.0 + */ +public class DefaultContextDataFactory implements ContextDataFactory { + private final SortedArrayStringMap emptyMap = new SortedArrayStringMap(0); + + public DefaultContextDataFactory() { + emptyMap.freeze(); + } + + @Override + public StringMap createContextData() { + return new SortedArrayStringMap(); + } + + @Override + public StringMap createContextData(final int initialCapacity) { + return new SortedArrayStringMap(initialCapacity); + } + + @Override + public StringMap emptyFrozenContextData() { + return emptyMap; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java index bcdd46c8b97..bd33c1ec7a6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.impl; +import java.util.List; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.ContextDataInjector; @@ -24,39 +26,30 @@ import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.plugins.ContextScoped; import org.apache.logging.log4j.plugins.Inject; -import org.apache.logging.log4j.plugins.di.DI; -import org.apache.logging.log4j.util.StringMap; - -import java.util.List; /** * Always creates new LogEvent instances. */ +@ContextScoped public class DefaultLogEventFactory implements LogEventFactory { - public static DefaultLogEventFactory newInstance() { - final var injector = DI.createInjector(); - injector.init(); - return injector.getInstance(DefaultLogEventFactory.class); - } - - private final ContextDataInjector injector; + private final ContextDataInjector contextDataInjector; + private final ContextDataFactory contextDataFactory; private final Clock clock; private final NanoClock nanoClock; @Inject public DefaultLogEventFactory( - final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock) { - this.injector = injector; + final ContextDataInjector contextDataInjector, final ContextDataFactory contextDataFactory, + final Clock clock, final NanoClock nanoClock) { + this.contextDataInjector = contextDataInjector; + this.contextDataFactory = contextDataFactory; this.clock = clock; this.nanoClock = nanoClock; } - private StringMap createContextData(final List properties) { - return injector.injectContextData(properties, ContextDataFactory.createContextData()); - } - /** * Creates a log event. * @@ -73,15 +66,17 @@ private StringMap createContextData(final List properties) { public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn, final Level level, final Message data, final List properties, final Throwable t) { - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setNanoTime(nanoClock.nanoTime()) + .setContextDataInjector(contextDataInjector) + .setContextDataFactory(contextDataFactory) .setClock(clock) .setLoggerName(loggerName) .setMarker(marker) .setLoggerFqcn(fqcn) .setLevel(level) .setMessage(data) - .setContextData(createContextData(properties)) + .setContextData(properties) .setThrown(t) .build(); } @@ -103,8 +98,10 @@ public LogEvent createEvent(final String loggerName, final Marker marker, public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn, final StackTraceElement location, final Level level, final Message data, final List properties, final Throwable t) { - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setNanoTime(nanoClock.nanoTime()) + .setContextDataInjector(contextDataInjector) + .setContextDataFactory(contextDataFactory) .setClock(clock) .setLoggerName(loggerName) .setMarker(marker) @@ -112,8 +109,8 @@ public LogEvent createEvent(final String loggerName, final Marker marker, final .setSource(location) .setLevel(level) .setMessage(data) - .setContextData(createContextData(properties)) + .setContextData(properties) .setThrown(t) - .build(); + .toImmutable(); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java index 820d7ac0ccb..a85e2482e74 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ExtendedClassInfo.java @@ -18,6 +18,7 @@ import java.io.Serializable; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; import org.apache.logging.log4j.core.pattern.PlainTextRenderer; import org.apache.logging.log4j.core.pattern.TextRenderer; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ImmutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ImmutableLogEvent.java new file mode 100644 index 00000000000..4f9a2846e7a --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ImmutableLogEvent.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.impl; + +import java.util.Objects; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.core.time.MutableInstant; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.ReusableMessage; +import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.StackLocatorUtil; +import org.apache.logging.log4j.util.StringMap; + +public class ImmutableLogEvent implements LogEvent { + private final StringMap contextData; + private final ThreadContext.ContextStack contextStack; + private final String loggerFqcn; + private final Level level; + private final String loggerName; + private final Marker marker; + private Message message; + private final MutableInstant instant = new MutableInstant(); + private StackTraceElement source; + private String threadName; + private long threadId; + private int threadPriority; + private final Throwable thrown; + ThrowableProxy thrownProxy; + private boolean endOfBatch; + private boolean includeLocation; + private final long nanoTime; + + ImmutableLogEvent(final String loggerName, final Marker marker, final String loggerFqcn, final Level level, + final Message message, final Throwable thrown, final ThrowableProxy thrownProxy, + final StringMap contextData, final ThreadContext.ContextStack contextStack, + final long threadId, final String threadName, final int threadPriority, + final StackTraceElement source, final Instant instant, final long nanoTime, + final boolean endOfBatch, final boolean includeLocation) { + this.loggerName = loggerName; + this.marker = marker; + this.loggerFqcn = loggerFqcn; + this.level = level; + this.message = message; + this.thrown = thrown; + this.thrownProxy = thrownProxy; + this.contextData = contextData; + this.contextStack = contextStack; + this.threadId = threadId; + this.threadName = threadName; + this.threadPriority = threadPriority; + this.source = source; + this.instant.initFrom(instant); + this.nanoTime = nanoTime; + this.endOfBatch = endOfBatch; + this.includeLocation = includeLocation; + } + + @Override + public StringMap getContextData() { + return contextData; + } + + @Override + public ThreadContext.ContextStack getContextStack() { + return contextStack; + } + + @Override + public String getLoggerFqcn() { + return loggerFqcn; + } + + @Override + public Level getLevel() { + return level; + } + + @Override + public String getLoggerName() { + return loggerName; + } + + @Override + public Marker getMarker() { + return marker; + } + + @Override + public Message getMessage() { + return message; + } + + @Override + public MutableInstant getInstant() { + return instant; + } + + @Override + public StackTraceElement getSource() { + if (source != null) { + return source; + } + if (loggerFqcn == null || !includeLocation) { + return null; + } + source = StackLocatorUtil.calcLocation(loggerFqcn); + return source; + } + + StackTraceElement getSourceOrNull() { + return source; + } + + @Override + public String getThreadName() { + if (threadName == null) { + threadName = Thread.currentThread().getName(); + } + return threadName; + } + + String getThreadNameOrNull() { + return threadName; + } + + @Override + public long getThreadId() { + if (threadId == 0) { + threadId = Thread.currentThread().getId(); + } + return threadId; + } + + long getThreadIdOrZero() { + return threadId; + } + + @Override + public int getThreadPriority() { + if (threadPriority == 0) { + threadPriority = Thread.currentThread().getPriority(); + } + return threadPriority; + } + + int getThreadPriorityOrZero() { + return threadPriority; + } + + @Override + public Throwable getThrown() { + return thrown; + } + + @Override + public ThrowableProxy getThrownProxy() { + if (thrownProxy == null && thrown != null) { + thrownProxy = new ThrowableProxy(thrown); + } + return thrownProxy; + } + + ThrowableProxy getThrownProxyOrNull() { + return thrownProxy; + } + + @Override + public boolean isEndOfBatch() { + return endOfBatch; + } + + @Override + public boolean isIncludeLocation() { + return includeLocation; + } + + @Override + public long getNanoTime() { + return nanoTime; + } + + @Override + public LogEvent toImmutable() { + if (message instanceof ReusableMessage) { + freezeMessage(); + } + return this; + } + + @InternalApi + public void freezeMessage() { + final Message message = this.message; + this.message = new MementoMessage(message.getFormattedMessage(), message.getFormat(), message.getParameters()); + } + + @Override + public long getTimeMillis() { + return instant.getEpochMillisecond(); + } + + @Override + public void setEndOfBatch(final boolean endOfBatch) { + this.endOfBatch = endOfBatch; + } + + @Override + public void setIncludeLocation(final boolean locationRequired) { + this.includeLocation = locationRequired; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + final String n = loggerName.isEmpty() ? LoggerConfig.ROOT : loggerName; + sb.append("Logger=").append(n); + sb.append(" Level=").append(level.name()); + sb.append(" Message=").append(message == null ? null : message.getFormattedMessage()); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final ImmutableLogEvent that = (ImmutableLogEvent) o; + return threadId == that.threadId + && threadPriority == that.threadPriority + && endOfBatch == that.endOfBatch + && includeLocation == that.includeLocation + && nanoTime == that.nanoTime + && Objects.equals(contextData, that.contextData) + && Objects.equals(contextStack, that.contextStack) + && Objects.equals(loggerFqcn, that.loggerFqcn) + && level.equals(that.level) + && loggerName.equals(that.loggerName) + && Objects.equals(marker, that.marker) + && message.equals(that.message) + && instant.equals(that.instant) + && Objects.equals(source, that.source) + && Objects.equals(threadName, that.threadName) + && Objects.equals(thrown, that.thrown) + && Objects.equals(thrownProxy, that.thrownProxy); + } + + @Override + public int hashCode() { + return Objects.hash(contextData, contextStack, loggerFqcn, level, loggerName, marker, message, instant, source, + threadName, threadId, threadPriority, thrown, thrownProxy, endOfBatch, includeLocation, nanoTime); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java index 41e071e0958..1253b30803f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java @@ -21,6 +21,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LoggerContext; @@ -29,10 +31,10 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.DefaultConfiguration; +import org.apache.logging.log4j.core.config.LoggerContextNamingStrategy; import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.util.Cancellable; -import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Singleton; @@ -40,7 +42,7 @@ import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.spi.LoggerContextFactory; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; import static org.apache.logging.log4j.util.Constants.isWebApp; @@ -52,89 +54,36 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba private static final StatusLogger LOGGER = StatusLogger.getLogger(); - private final Injector injector; - private final ContextSelector selector; + private final Supplier namingStrategySupplier; + private final Supplier contextSelectorSupplier; + + private final PropertyResolver propertyResolver; private final ShutdownCallbackRegistry shutdownCallbackRegistry; - /** - * Initializes the ContextSelector from system property {@link Constants#LOG4J_CONTEXT_SELECTOR}. - */ public Log4jContextFactory() { - injector = DI.createInjector(); - injector.init(); - this.selector = injector.getInstance(ContextSelector.KEY); - this.shutdownCallbackRegistry = injector.getInstance(ShutdownCallbackRegistry.KEY); - LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass()); - initializeShutdownCallbackRegistry(); - } - - /** - * Initializes this factory's ContextSelector with the specified selector. - * @param selector the selector to use - */ - public Log4jContextFactory(final ContextSelector selector) { - Objects.requireNonNull(selector, "No ContextSelector provided"); - injector = DI.createInjector(); - injector.init(); - injector.registerBinding(ContextSelector.KEY, () -> selector); - this.selector = injector.getInstance(ContextSelector.KEY); - this.shutdownCallbackRegistry = injector.getInstance(ShutdownCallbackRegistry.KEY); - LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass()); - initializeShutdownCallbackRegistry(); - } - - /** - * Constructs a Log4jContextFactory using the ContextSelector from {@link Constants#LOG4J_CONTEXT_SELECTOR} - * and the provided ShutdownRegistrationStrategy. - * - * @param shutdownCallbackRegistry the ShutdownRegistrationStrategy to use - * @since 2.1 - */ - public Log4jContextFactory(final ShutdownCallbackRegistry shutdownCallbackRegistry) { - Objects.requireNonNull(shutdownCallbackRegistry, "No ShutdownCallbackRegistry provided"); - injector = DI.createInjector(); - injector.init(); - injector.registerBinding(ShutdownCallbackRegistry.KEY, () -> shutdownCallbackRegistry); - this.selector = injector.getInstance(ContextSelector.KEY); - this.shutdownCallbackRegistry = injector.getInstance(ShutdownCallbackRegistry.KEY); - LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass()); - initializeShutdownCallbackRegistry(); - } - - /** - * Constructs a Log4jContextFactory using the provided ContextSelector and ShutdownRegistrationStrategy. - * - * @param selector the selector to use - * @param shutdownCallbackRegistry the ShutdownRegistrationStrategy to use - * @since 2.1 - */ - public Log4jContextFactory(final ContextSelector selector, - final ShutdownCallbackRegistry shutdownCallbackRegistry) { - Objects.requireNonNull(selector, "No ContextSelector provided"); - Objects.requireNonNull(shutdownCallbackRegistry, "No ShutdownCallbackRegistry provided"); - injector = DI.createInjector(); + Injector injector = DI.createInjector(); injector.init(); - injector.registerBinding(ContextSelector.KEY, () -> selector) - .registerBinding(ShutdownCallbackRegistry.KEY, () -> shutdownCallbackRegistry); - this.selector = injector.getInstance(ContextSelector.KEY); + namingStrategySupplier = injector.getFactory(LoggerContextNamingStrategy.class); + contextSelectorSupplier = injector.getFactory(ContextSelector.KEY); + this.propertyResolver = injector.getInstance(PropertyResolver.class); this.shutdownCallbackRegistry = injector.getInstance(ShutdownCallbackRegistry.KEY); LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass()); initializeShutdownCallbackRegistry(); } @Inject - public Log4jContextFactory(final Injector injector, final ContextSelector selector, final ShutdownCallbackRegistry registry) { - this.injector = injector; - this.selector = selector; - this.shutdownCallbackRegistry = registry; - LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass()); + public Log4jContextFactory(final Supplier namingStrategySupplier, + final Supplier contextSelectorSupplier, + final ShutdownCallbackRegistry registry, + final PropertyResolver resolver) { + this.namingStrategySupplier = namingStrategySupplier; + this.contextSelectorSupplier = contextSelectorSupplier; + shutdownCallbackRegistry = registry; + propertyResolver = resolver; + LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass()); initializeShutdownCallbackRegistry(); } - public Log4jContextFactory(final Injector injector) { - this(injector, injector.getInstance(ContextSelector.KEY), injector.getInstance(ShutdownCallbackRegistry.KEY)); - } - private void initializeShutdownCallbackRegistry() { if (isShutdownHookEnabled() && this.shutdownCallbackRegistry instanceof LifeCycle) { try { @@ -160,7 +109,9 @@ private void initializeShutdownCallbackRegistry() { @Override public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext) { - final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext); + final String name = namingStrategySupplier.get() + .getName(null, loader, externalContext, null); + final LoggerContext ctx = getSelector().getContext(fqcn, name, loader, currentContext); if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } @@ -182,14 +133,16 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin */ public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext, final ConfigurationSource source) { - final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null); + final String name = namingStrategySupplier.get() + .getName(source != null ? source.getURI() : null, loader, externalContext, null); + final LoggerContext ctx = getSelector().getContext(fqcn, name, loader, currentContext, null); if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } if (ctx.getState() == LifeCycle.State.INITIALIZED) { if (source != null) { ContextAnchor.THREAD_CONTEXT.set(ctx); - final Configuration config = injector.getInstance(ConfigurationFactory.KEY).getConfiguration(ctx, source); + final Configuration config = ctx.getInstance(ConfigurationFactory.class).getConfiguration(ctx, source); LOGGER.debug("Starting {} from configuration {}", ctx, source); ctx.start(config); ContextAnchor.THREAD_CONTEXT.remove(); @@ -212,7 +165,8 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin */ public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext, final Configuration configuration) { - final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null); + final String name = configuration.getName(); + final LoggerContext ctx = getSelector().getContext(fqcn, name, loader, currentContext, null); if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } @@ -235,23 +189,23 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin * @param currentContext If true returns the current Context, if false returns the Context appropriate * for the caller if a more appropriate Context can be determined. * @param configLocation The location of the configuration for the LoggerContext (or null). + * @param name The name of the LoggerContext (or null). * @return The LoggerContext. */ @Override public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext, final URI configLocation, final String name) { - final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation); + final String contextName = Objects.requireNonNullElse(name, namingStrategySupplier.get() + .getName(configLocation, loader, externalContext, null)); + final LoggerContext ctx = getSelector().getContext(fqcn, contextName, loader, currentContext, configLocation); if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } - if (name != null) { - ctx.setName(name); - } if (ctx.getState() == LifeCycle.State.INITIALIZED) { if (configLocation != null || name != null) { ContextAnchor.THREAD_CONTEXT.set(ctx); final Configuration config = - injector.getInstance(ConfigurationFactory.KEY).getConfiguration(ctx, name, configLocation); + ctx.getInstance(ConfigurationFactory.class).getConfiguration(ctx, name, configLocation); LOGGER.debug("Starting {} from configuration at {}", ctx, configLocation); ctx.start(config); ContextAnchor.THREAD_CONTEXT.remove(); @@ -264,15 +218,40 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Map.Entry entry, final boolean currentContext, final URI configLocation, final String name) { - final LoggerContext ctx = selector.getContext(fqcn, loader, entry, currentContext, configLocation); - if (name != null) { - ctx.setName(name); + final String contextName = Objects.requireNonNullElse(name, namingStrategySupplier.get() + .getName(configLocation, loader, null, entry)); + final LoggerContext ctx = getSelector() + .getContext(fqcn, contextName, loader, entry, currentContext, configLocation); + if (ctx.getState() == LifeCycle.State.INITIALIZED) { + if (configLocation != null || name != null) { + ContextAnchor.THREAD_CONTEXT.set(ctx); + final Configuration config = + ctx.getInstance(ConfigurationFactory.class).getConfiguration(ctx, name, configLocation, loader); + LOGGER.debug("Starting {} from configuration at {}", ctx, configLocation); + ctx.start(config); + ContextAnchor.THREAD_CONTEXT.remove(); + } else { + ctx.start(); + } } + return ctx; + } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + final URI configLocation, final String name, final Consumer configurer) { + final String contextName = Objects.requireNonNullElse(name, namingStrategySupplier.get() + .getName(configLocation, loader, null, null)); + final LoggerContext ctx = getSelector() + .getContext(fqcn, contextName, loader, currentContext, configLocation); if (ctx.getState() == LifeCycle.State.INITIALIZED) { if (configLocation != null || name != null) { ContextAnchor.THREAD_CONTEXT.set(ctx); + final Injector injector = ctx.getInjector(); + if (configurer != null) { + configurer.accept(injector); + } final Configuration config = - injector.getInstance(ConfigurationFactory.KEY).getConfiguration(ctx, name, configLocation); + ctx.getInstance(ConfigurationFactory.class).getConfiguration(ctx, name, configLocation, loader); LOGGER.debug("Starting {} from configuration at {}", ctx, configLocation); ctx.start(config); ContextAnchor.THREAD_CONTEXT.remove(); @@ -285,21 +264,21 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext, final List configLocations, final String name) { - final LoggerContext ctx = selector - .getContext(fqcn, loader, currentContext, null/*this probably needs to change*/); + // TODO(ms): consider if we should pass any particular URI or if the URI is pointless info + final String contextName = Objects.requireNonNullElse(name, namingStrategySupplier.get() + .getName(null, loader, externalContext, null)); + final LoggerContext ctx = getSelector() + .getContext(fqcn, contextName, loader, currentContext, null/*this probably needs to change*/); if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } - if (name != null) { - ctx.setName(name); - } if (ctx.getState() == LifeCycle.State.INITIALIZED) { if ((configLocations != null && !configLocations.isEmpty())) { ContextAnchor.THREAD_CONTEXT.set(ctx); final List configurations = new ArrayList<>(configLocations.size()); for (final URI configLocation : configLocations) { - final Configuration currentReadConfiguration = injector.getInstance(ConfigurationFactory.KEY) - .getConfiguration(ctx, name, configLocation); + final Configuration currentReadConfiguration = + ctx.getInstance(ConfigurationFactory.class).getConfiguration(ctx, name, configLocation); if (currentReadConfiguration != null) { if (currentReadConfiguration instanceof DefaultConfiguration) { LOGGER.warn("Unable to locate configuration {}, ignoring", configLocation.toString()); @@ -333,8 +312,8 @@ else if (currentReadConfiguration instanceof AbstractConfiguration) { @Override public void shutdown(final String fqcn, final ClassLoader loader, final boolean currentContext, final boolean allContexts) { - if (selector.hasContext(fqcn, loader, currentContext)) { - selector.shutdown(fqcn, loader, currentContext, allContexts); + if (getSelector().hasContext(fqcn, loader, currentContext)) { + getSelector().shutdown(fqcn, loader, currentContext, allContexts); } } @@ -349,7 +328,7 @@ public void shutdown(final String fqcn, final ClassLoader loader, final boolean */ @Override public boolean hasContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { - return selector.hasContext(fqcn, loader, currentContext); + return getSelector().hasContext(fqcn, loader, currentContext); } /** @@ -357,7 +336,7 @@ public boolean hasContext(final String fqcn, final ClassLoader loader, final boo * @return The ContextSelector. */ public ContextSelector getSelector() { - return selector; + return contextSelectorSupplier.get(); } /** @@ -378,13 +357,13 @@ public ShutdownCallbackRegistry getShutdownCallbackRegistry() { @Override public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) { if (context instanceof LoggerContext) { - selector.removeContext((LoggerContext) context); + getSelector().removeContext((LoggerContext) context); } } @Override public boolean isClassLoaderDependent() { - return selector.isClassLoaderDependent(); + return getSelector().isClassLoaderDependent(); } @Override @@ -393,7 +372,6 @@ public Cancellable addShutdownCallback(final Runnable callback) { } public boolean isShutdownHookEnabled() { - return !isWebApp() && PropertiesUtil.getProperties() - .getBooleanProperty(Log4jProperties.SHUTDOWN_HOOK_ENABLED, true); + return !isWebApp(propertyResolver) && propertyResolver.getBoolean(Log4jProperties.SHUTDOWN_HOOK_ENABLED, true); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java deleted file mode 100644 index 28be3a64057..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ /dev/null @@ -1,846 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.impl; - -import java.io.IOException; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.rmi.MarshalledObject; -import java.util.Objects; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.ContextDataInjector; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.async.RingBufferLogEvent; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.time.Clock; -import org.apache.logging.log4j.core.time.ClockFactory; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.message.LoggerNameAwareMessage; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.message.ReusableMessage; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.message.TimestampMessage; -import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.util.StackLocatorUtil; -import org.apache.logging.log4j.util.StringMap; -import org.apache.logging.log4j.util.Strings; - -/** - * Implementation of a LogEvent. - */ -public class Log4jLogEvent implements LogEvent { - - private static final long serialVersionUID = -8393305700508709443L; - - private final String loggerFqcn; - private final Marker marker; - private final Level level; - private final String loggerName; - private Message message; - private final MutableInstant instant = new MutableInstant(); - private final transient Throwable thrown; - private ThrowableProxy thrownProxy; - private final StringMap contextData; - private final ThreadContext.ContextStack contextStack; - private long threadId; - private String threadName; - private int threadPriority; - private StackTraceElement source; - private boolean includeLocation; - private boolean endOfBatch = false; - /** @since Log4J 2.4 */ - private final transient long nanoTime; - - /** LogEvent Builder helper class. */ - public static class Builder implements org.apache.logging.log4j.plugins.util.Builder { - - private String loggerFqcn; - private Marker marker; - private Level level; - private String loggerName; - private Message message; - private Throwable thrown; - private final MutableInstant instant = new MutableInstant(); - private ThrowableProxy thrownProxy; - private StringMap contextData; - private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack(); - private long threadId; - private String threadName; - private int threadPriority; - private StackTraceElement source; - private boolean includeLocation; - private boolean endOfBatch = false; - private long nanoTime; - private Clock clock; - private ContextDataInjector contextDataInjector; - - public Builder() { - initDefaultContextData(); - } - - public Builder(final LogEvent other) { - Objects.requireNonNull(other); - if (other instanceof RingBufferLogEvent) { - ((RingBufferLogEvent) other).initializeBuilder(this); - return; - } - if (other instanceof MutableLogEvent) { - ((MutableLogEvent) other).initializeBuilder(this); - return; - } - this.loggerFqcn = other.getLoggerFqcn(); - this.marker = other.getMarker(); - this.level = other.getLevel(); - this.loggerName = other.getLoggerName(); - this.message = other.getMessage(); - this.instant.initFrom(other.getInstant()); - this.thrown = other.getThrown(); - this.contextStack = other.getContextStack(); - this.includeLocation = other.isIncludeLocation(); - this.endOfBatch = other.isEndOfBatch(); - this.nanoTime = other.getNanoTime(); - - initDefaultContextData(); - // Avoid unnecessarily initializing thrownProxy, threadName and source if possible - if (other instanceof Log4jLogEvent) { - final Log4jLogEvent evt = (Log4jLogEvent) other; - this.contextData = evt.contextData; - this.thrownProxy = evt.thrownProxy; - this.source = evt.source; - this.threadId = evt.threadId; - this.threadName = evt.threadName; - this.threadPriority = evt.threadPriority; - } else { - if (other.getContextData() instanceof StringMap) { - this.contextData = (StringMap) other.getContextData(); - } else { - if (this.contextData.isFrozen()) { - this.contextData = ContextDataFactory.createContextData(); - } else { - this.contextData.clear(); - } - this.contextData.putAll(other.getContextData()); - - } - this.thrownProxy = other.getThrownProxy(); - this.source = other.getSource(); - this.threadId = other.getThreadId(); - this.threadName = other.getThreadName(); - this.threadPriority = other.getThreadPriority(); - } - } - - public Builder setLevel(final Level level) { - this.level = level; - return this; - } - - public Builder setLoggerFqcn(final String loggerFqcn) { - this.loggerFqcn = loggerFqcn; - return this; - } - - public Builder setLoggerName(final String loggerName) { - this.loggerName = loggerName; - return this; - } - - public Builder setMarker(final Marker marker) { - this.marker = marker; - return this; - } - - public Builder setMessage(final Message message) { - this.message = message; - return this; - } - - public Builder setThrown(final Throwable thrown) { - this.thrown = thrown; - return this; - } - - public Builder setTimeMillis(final long timeMillis) { - this.instant.initFromEpochMilli(timeMillis, 0); - return this; - } - - public Builder setInstant(final Instant instant) { - this.instant.initFrom(instant); - return this; - } - - public Builder setThrownProxy(final ThrowableProxy thrownProxy) { - this.thrownProxy = thrownProxy; - return this; - } - - public Builder setContextData(final StringMap contextData) { - this.contextData = contextData; - return this; - } - - public Builder setContextStack(final ThreadContext.ContextStack contextStack) { - this.contextStack = contextStack; - return this; - } - - public Builder setThreadId(final long threadId) { - this.threadId = threadId; - return this; - } - - public Builder setThreadName(final String threadName) { - this.threadName = threadName; - return this; - } - - public Builder setThreadPriority(final int threadPriority) { - this.threadPriority = threadPriority; - return this; - } - - public Builder setSource(final StackTraceElement source) { - this.source = source; - return this; - } - - public Builder setIncludeLocation(final boolean includeLocation) { - this.includeLocation = includeLocation; - return this; - } - - public Builder setEndOfBatch(final boolean endOfBatch) { - this.endOfBatch = endOfBatch; - return this; - } - - /** - * Sets the nano time for the event. - * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event - * was created. - * @return this builder - */ - public Builder setNanoTime(final long nanoTime) { - this.nanoTime = nanoTime; - return this; - } - - public Builder setClock(final Clock clock) { - this.clock = clock; - return this; - } - - public Builder setContextDataInjector(final ContextDataInjector contextDataInjector) { - this.contextDataInjector = contextDataInjector; - return this; - } - - @Override - public Log4jLogEvent build() { - initTimeFields(); - final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown, - thrownProxy, contextData, contextStack, threadId, threadName, threadPriority, source, - instant.getEpochMillisecond(), instant.getNanoOfMillisecond(), nanoTime); - result.setIncludeLocation(includeLocation); - result.setEndOfBatch(endOfBatch); - return result; - } - - private void initTimeFields() { - if (instant.getEpochMillisecond() == 0) { - if (message instanceof TimestampMessage) { - instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0); - } else { - instant.initFrom(clock != null ? clock : ClockFactory.getClock()); - } - } - } - - private void initDefaultContextData() { - contextDataInjector = ContextDataInjectorFactory.createInjector(); - contextData = contextDataInjector.injectContextData(null, ContextDataFactory.createContextData()); - } - } - - /** - * Returns a new empty {@code Log4jLogEvent.Builder} with all fields empty. - * @return a new empty builder. - */ - public static Builder newBuilder() { - return new Builder().setLoggerName(Strings.EMPTY); - } - - public Log4jLogEvent() { - this(Strings.EMPTY, null, Strings.EMPTY, null, null, null, null, null, null, 0, null, 0, null, 0, 0, 0); - } - - /** - * Constructor. - * @param loggerName The name of the Logger. - * @param marker The Marker or null. - * @param loggerFQCN The fully qualified class name of the caller. - * @param level The logging Level. - * @param message The Message. - * @param thrown A Throwable or null. - * @param thrownProxy A ThrowableProxy or null. - * @param contextData The key-value pairs from the context. - * @param contextStack the nested diagnostic context. - * @param threadId the thread ID - * @param threadName The name of the thread. - * @param threadPriority the thread priority - * @param source The locations of the caller. - * @param timestampMillis The timestamp of the event. - * @param nanoOfMillisecond the nanoseconds within the millisecond, always positive, never exceeds {@code 999,999} - * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event was - * created. - */ - private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level, - final Message message, final Throwable thrown, final ThrowableProxy thrownProxy, - final StringMap contextData, final ThreadContext.ContextStack contextStack, final long threadId, - final String threadName, final int threadPriority, final StackTraceElement source, - final long timestampMillis, final int nanoOfMillisecond, final long nanoTime) { - this.loggerName = loggerName; - this.marker = marker; - this.loggerFqcn = loggerFQCN; - this.level = level == null ? Level.OFF : level; // LOG4J2-462, LOG4J2-465 - this.message = message; - this.thrown = thrown; - this.thrownProxy = thrownProxy; - this.contextData = contextData == null ? ContextDataFactory.createContextData() : contextData; - this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack; - this.threadId = threadId; - this.threadName = threadName; - this.threadPriority = threadPriority; - this.source = source; - if (message instanceof LoggerNameAwareMessage) { - ((LoggerNameAwareMessage) message).setLoggerName(loggerName); - } - this.nanoTime = nanoTime; - final long millis = message instanceof TimestampMessage - ? ((TimestampMessage) message).getTimestamp() - : timestampMillis; - instant.initFromEpochMilli(millis, nanoOfMillisecond); - } - - /** - * Returns a new fully initialized {@code Log4jLogEvent.Builder} containing a copy of all fields of this event. - * @return a new fully initialized builder. - */ - public Builder asBuilder() { - return new Builder(this); - } - - @Override - public Log4jLogEvent toImmutable() { - if (getMessage() instanceof ReusableMessage) { - makeMessageImmutable(); - } - return this; - } - - /** - * Returns the logging Level. - * @return the Level associated with this event. - */ - @Override - public Level getLevel() { - return level; - } - - /** - * Returns the name of the Logger used to generate the event. - * @return The Logger name. - */ - @Override - public String getLoggerName() { - return loggerName; - } - - /** - * Returns the Message associated with the event. - * @return The Message. - */ - @Override - public Message getMessage() { - return message; - } - - public void makeMessageImmutable() { - message = new MementoMessage(message.getFormattedMessage(), message.getFormat(), message.getParameters()); - } - - @Override - public long getThreadId() { - if (threadId == 0) { - threadId = Thread.currentThread().getId(); - } - return threadId; - } - - /** - * Returns the name of the Thread on which the event was generated. - * @return The name of the Thread. - */ - @Override - public String getThreadName() { - if (threadName == null) { - threadName = Thread.currentThread().getName(); - } - return threadName; - } - - @Override - public int getThreadPriority() { - if (threadPriority == 0) { - threadPriority = Thread.currentThread().getPriority(); - } - return threadPriority; - } - - /** - * {@inheritDoc} - */ - @Override - public long getTimeMillis() { - return instant.getEpochMillisecond(); - } - - /** - * {@inheritDoc} - * @since 2.11.0 - */ - @Override - public Instant getInstant() { - return instant; - } - - /** - * Returns the Throwable associated with the event, or null. - * @return The Throwable associated with the event. - */ - @Override - public Throwable getThrown() { - return thrown; - } - - /** - * Returns the ThrowableProxy associated with the event, or null. - * @return The ThrowableProxy associated with the event. - */ - @Override - public ThrowableProxy getThrownProxy() { - if (thrownProxy == null && thrown != null) { - thrownProxy = new ThrowableProxy(thrown); - } - return thrownProxy; - } - - - /** - * Returns the Marker associated with the event, or null. - * @return the Marker associated with the event. - */ - @Override - public Marker getMarker() { - return marker; - } - - /** - * The fully qualified class name of the class that was called by the caller. - * @return the fully qualified class name of the class that is performing logging. - */ - @Override - public String getLoggerFqcn() { - return loggerFqcn; - } - - /** - * Returns the {@code ReadOnlyStringMap} containing context data key-value pairs. - * @return the {@code ReadOnlyStringMap} containing context data key-value pairs - * @since 2.7 - */ - @Override - public ReadOnlyStringMap getContextData() { - return contextData; - } - - /** - * Returns an immutable copy of the ThreadContext stack. - * @return The context Stack. - */ - @Override - public ThreadContext.ContextStack getContextStack() { - return contextStack; - } - - /** - * Returns the StackTraceElement for the caller. This will be the entry that occurs right - * before the first occurrence of FQCN as a class name. - * @return the StackTraceElement for the caller. - */ - @Override - public StackTraceElement getSource() { - if (source != null) { - return source; - } - if (loggerFqcn == null || !includeLocation) { - return null; - } - source = StackLocatorUtil.calcLocation(loggerFqcn); - return source; - } - - @Override - public boolean isIncludeLocation() { - return includeLocation; - } - - @Override - public void setIncludeLocation(final boolean includeLocation) { - this.includeLocation = includeLocation; - } - - @Override - public boolean isEndOfBatch() { - return endOfBatch; - } - - @Override - public void setEndOfBatch(final boolean endOfBatch) { - this.endOfBatch = endOfBatch; - } - - @Override - public long getNanoTime() { - return nanoTime; - } - - /** - * Creates a LogEventProxy that can be serialized. - * @return a LogEventProxy. - */ - protected Object writeReplace() { - getThrownProxy(); // ensure ThrowableProxy is initialized - return new LogEventProxy(this, this.includeLocation); - } - - /** - * Take a snapshot of the specified {@code LogEvent}. - * - * @param event the event to take a snapshot of - * @param includeLocation if true, this method will obtain caller location information - * @return snapshot of the event as a {@code Serializable} object - * @see #deserialize(Serializable) - * @see #serialize(Log4jLogEvent, boolean) - */ - public static Serializable serialize(final LogEvent event, final boolean includeLocation) { - if (event instanceof Log4jLogEvent) { - event.getThrownProxy(); // ensure ThrowableProxy is initialized - return new LogEventProxy((Log4jLogEvent) event, includeLocation); - } - return new LogEventProxy(event, includeLocation); - } - - /** - * Take a snapshot of the specified {@code Log4jLogEvent}. - * - * @param event the event to take a snapshot of - * @param includeLocation if true, this method will obtain caller location information - * @return snapshot of the event as a {@code Serializable} object - * @see #deserialize(Serializable) - * @see #serialize(LogEvent, boolean) - */ - public static Serializable serialize(final Log4jLogEvent event, final boolean includeLocation) { - event.getThrownProxy(); // ensure ThrowableProxy is initialized - return new LogEventProxy(event, includeLocation); - } - - public static boolean canDeserialize(final Serializable event) { - return event instanceof LogEventProxy; - } - - public static Log4jLogEvent deserialize(final Serializable event) { - Objects.requireNonNull(event, "Event cannot be null"); - if (event instanceof LogEventProxy) { - final LogEventProxy proxy = (LogEventProxy) event; - final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker, - proxy.loggerFQCN, proxy.level, proxy.message, - proxy.thrown, proxy.thrownProxy, proxy.contextData, proxy.contextStack, proxy.threadId, - proxy.threadName, proxy.threadPriority, proxy.source, proxy.timeMillis, proxy.nanoOfMillisecond, - proxy.nanoTime); - result.setEndOfBatch(proxy.isEndOfBatch); - result.setIncludeLocation(proxy.isLocationRequired); - return result; - } - throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString()); - } - - private void readObject(final ObjectInputStream stream) throws InvalidObjectException { - throw new InvalidObjectException("Proxy required"); - } - - public static LogEvent createMemento(final LogEvent logEvent) { - return new Log4jLogEvent.Builder(logEvent).build(); - } - - /** - * Creates and returns a new immutable copy of this {@code Log4jLogEvent}. - * - * @return a new immutable copy of the data in this {@code Log4jLogEvent} - */ - public static Log4jLogEvent createMemento(final LogEvent event, final boolean includeLocation) { - return deserialize(serialize(event, includeLocation)); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - final String n = loggerName.isEmpty() ? LoggerConfig.ROOT : loggerName; - sb.append("Logger=").append(n); - sb.append(" Level=").append(level.name()); - sb.append(" Message=").append(message == null ? null : message.getFormattedMessage()); - return sb.toString(); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final Log4jLogEvent that = (Log4jLogEvent) o; - - if (endOfBatch != that.endOfBatch) { - return false; - } - if (includeLocation != that.includeLocation) { - return false; - } - if (!instant.equals(that.instant)) { - return false; - } - if (nanoTime != that.nanoTime) { - return false; - } - if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) { - return false; - } - if (level != null ? !level.equals(that.level) : that.level != null) { - return false; - } - if (source != null ? !source.equals(that.source) : that.source != null) { - return false; - } - if (marker != null ? !marker.equals(that.marker) : that.marker != null) { - return false; - } - if (contextData != null ? !contextData.equals(that.contextData) : that.contextData != null) { - return false; - } - if (!message.equals(that.message)) { - return false; - } - if (!loggerName.equals(that.loggerName)) { - return false; - } - if (contextStack != null ? !contextStack.equals(that.contextStack) : that.contextStack != null) { - return false; - } - if (threadId != that.threadId) { - return false; - } - if (threadName != null ? !threadName.equals(that.threadName) : that.threadName != null) { - return false; - } - if (threadPriority != that.threadPriority) { - return false; - } - if (!Objects.equals(thrown, that.thrown)) { - return false; - } - if (!Objects.equals(thrownProxy, that.thrownProxy)) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - // Check:OFF: MagicNumber - int result = loggerFqcn != null ? loggerFqcn.hashCode() : 0; - result = 31 * result + (marker != null ? marker.hashCode() : 0); - result = 31 * result + (level != null ? level.hashCode() : 0); - result = 31 * result + loggerName.hashCode(); - result = 31 * result + message.hashCode(); - result = 31 * result + instant.hashCode(); - result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32)); - result = 31 * result + (thrown != null ? thrown.hashCode() : 0); - result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0); - result = 31 * result + (contextData != null ? contextData.hashCode() : 0); - result = 31 * result + (contextStack != null ? contextStack.hashCode() : 0); - result = 31 * result + (int) (threadId ^ (threadId >>> 32)); - result = 31 * result + (threadName != null ? threadName.hashCode() : 0); - result = 31 * result + threadPriority; - result = 31 * result + (source != null ? source.hashCode() : 0); - result = 31 * result + (includeLocation ? 1 : 0); - result = 31 * result + (endOfBatch ? 1 : 0); - // Check:ON: MagicNumber - return result; - } - - /** - * Proxy pattern used to serialize the LogEvent. - */ - static class LogEventProxy implements Serializable { - - private static final long serialVersionUID = -8634075037355293699L; - private final String loggerFQCN; - private final Marker marker; - private final Level level; - private final String loggerName; - // transient since 2.8 - private final transient Message message; - /** since 2.8 */ - private MarshalledObject marshalledMessage; - /** since 2.8 */ - private String messageString; - private final long timeMillis; - /** since 2.11 */ - private final int nanoOfMillisecond; - private final transient Throwable thrown; - private final ThrowableProxy thrownProxy; - /** @since 2.7 */ - private final StringMap contextData; - private final ThreadContext.ContextStack contextStack; - /** @since 2.6 */ - private final long threadId; - private final String threadName; - /** @since 2.6 */ - private final int threadPriority; - private final StackTraceElement source; - private final boolean isLocationRequired; - private final boolean isEndOfBatch; - /** @since 2.4 */ - private final transient long nanoTime; - - public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) { - this.loggerFQCN = event.loggerFqcn; - this.marker = event.marker; - this.level = event.level; - this.loggerName = event.loggerName; - this.message = event.message instanceof ReusableMessage - ? memento((ReusableMessage) event.message) - : event.message; - this.timeMillis = event.instant.getEpochMillisecond(); - this.nanoOfMillisecond = event.instant.getNanoOfMillisecond(); - this.thrown = event.thrown; - this.thrownProxy = event.thrownProxy; - this.contextData = event.contextData; - this.contextStack = event.contextStack; - this.source = includeLocation ? event.getSource() : null; - this.threadId = event.getThreadId(); - this.threadName = event.getThreadName(); - this.threadPriority = event.getThreadPriority(); - this.isLocationRequired = includeLocation; - this.isEndOfBatch = event.endOfBatch; - this.nanoTime = event.nanoTime; - } - - public LogEventProxy(final LogEvent event, final boolean includeLocation) { - this.loggerFQCN = event.getLoggerFqcn(); - this.marker = event.getMarker(); - this.level = event.getLevel(); - this.loggerName = event.getLoggerName(); - - final Message temp = event.getMessage(); - message = temp instanceof ReusableMessage - ? memento((ReusableMessage) temp) - : temp; - this.timeMillis = event.getInstant().getEpochMillisecond(); - this.nanoOfMillisecond = event.getInstant().getNanoOfMillisecond(); - this.thrown = event.getThrown(); - this.thrownProxy = event.getThrownProxy(); - this.contextData = memento(event.getContextData()); - this.contextStack = event.getContextStack(); - this.source = includeLocation ? event.getSource() : null; - this.threadId = event.getThreadId(); - this.threadName = event.getThreadName(); - this.threadPriority = event.getThreadPriority(); - this.isLocationRequired = includeLocation; - this.isEndOfBatch = event.isEndOfBatch(); - this.nanoTime = event.getNanoTime(); - } - - private static Message memento(final ReusableMessage message) { - return message.memento(); - } - - private static StringMap memento(final ReadOnlyStringMap data) { - final StringMap result = ContextDataFactory.createContextData(); - result.putAll(data); - return result; - } - - private static MarshalledObject marshall(final Message msg) { - try { - return new MarshalledObject<>(msg); - } catch (final Exception ex) { - return null; - } - } - - private void writeObject(final java.io.ObjectOutputStream s) throws IOException { - this.messageString = message.getFormattedMessage(); - this.marshalledMessage = marshall(message); - s.defaultWriteObject(); - } - - /** - * Returns a Log4jLogEvent using the data in the proxy. - * @return Log4jLogEvent. - */ - protected Object readResolve() { - final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message(), thrown, - thrownProxy, contextData, contextStack, threadId, threadName, threadPriority, source, timeMillis, - nanoOfMillisecond, nanoTime); - result.setEndOfBatch(isEndOfBatch); - result.setIncludeLocation(isLocationRequired); - return result; - } - - private Message message() { - if (marshalledMessage != null) { - try { - return marshalledMessage.get(); - } catch (final Exception ex) { - // ignore me - } - } - return new SimpleMessage(messageString); - } - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProperties.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProperties.java index 62a2a710e7f..90f98e4558e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProperties.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProperties.java @@ -17,124 +17,82 @@ package org.apache.logging.log4j.core.impl; public class Log4jProperties { - // TODO: rename properties according to established theme in - // https://cwiki.apache.org/confluence/display/LOGGING/Properties+Enhancement + @Deprecated // should use DI bindings + public static final String SHUTDOWN_CALLBACK_REGISTRY_CLASS_NAME = "log4j2.*.LoggerContext.shutdownCallbackRegistry"; + public static final String SHUTDOWN_HOOK_ENABLED = "log4j2.*.LoggerContext.shutdownHookEnabled"; - // LoggerContext.shutdownCallbackRegistry - public static final String SHUTDOWN_CALLBACK_REGISTRY_CLASS_NAME = "log4j2.shutdownCallbackRegistry"; - // LoggerContext.shutdownHookEnabled - public static final String SHUTDOWN_HOOK_ENABLED = "log4j2.shutdownHookEnabled"; + public static final String LOGGER_CONTEXT_STACKTRACE_ON_START = "log4j2.*.LoggerContext.stacktraceOnStart"; - // LoggerContext.stacktraceOnStart - public static final String LOGGER_CONTEXT_STACKTRACE_ON_START = "log4j2.LoggerContext.stacktraceOnStart"; + public static final String JANSI_ENABLED = "log4j2.*.Jansi.enabled"; - // Jansi.enabled - public static final String JANSI_DISABLED = "log4j2.skipJansi"; + @Deprecated // should use DI bindings + public static final String CONTEXT_SELECTOR_CLASS_NAME = "log4j2.*.LoggerContext.contextSelector"; - // LoggerContext.contextSelector - public static final String CONTEXT_SELECTOR_CLASS_NAME = "log4j2.contextSelector"; + public static final String STATUS_DEFAULT_LEVEL = "log4j2.*.StatusLogger.defaultStatusLevel"; - // LoggerContext.logEventFactory - public static final String LOG_EVENT_FACTORY_CLASS_NAME = "log4j2.logEventFactory"; + public static final String CONFIG_DEFAULT_LEVEL = "log4j2.*.Configuration.level"; + @Deprecated // should use DI bindings + public static final String CONFIG_CLOCK = "log4j2.*.Configuration.clock"; + @Deprecated // should use DI bindings + public static final String CONFIG_RELIABILITY_STRATEGY = "log4j2.*.Configuration.reliabilityStrategy"; + public static final String CONFIG_RELIABILITY_STRATEGY_AWAIT_UNCONDITIONALLY_MILLIS = "log4j2.*.Configuration.reliabilityStrategyAwaitUnconditionallyMillis"; + @Deprecated // should use DI bindings + public static final String CONFIG_CONFIGURATION_FACTORY_CLASS_NAME = "log4j2.*.Configuration.factory"; + public static final String CONFIG_LOCATION = "log4j2.*.Configuration.location"; + public static final String CONFIG_V1_LOCATION = "log4j2.*.V1Compatibility.location"; + public static final String CONFIG_V1_COMPATIBILITY_ENABLED = "log4j2.*.V1Compatibility.enabled"; + public static final String CONFIG_ALLOWED_PROTOCOLS = "log4j2.*.Configuration.allowedProtocols"; - // StatusLogger.defaultStatusLevel - public static final String STATUS_DEFAULT_LEVEL = "log4j2.defaultStatusLevel"; + public static final String ASYNC_LOGGER_FORMAT_MESSAGES_IN_BACKGROUND = "log4j2.*.AsyncLogger.formatMsgAsync"; + public static final String ASYNC_LOGGER_QUEUE_FULL_POLICY = "log4j2.*.AsyncLogger.queueFullPolicy"; + public static final String ASYNC_LOGGER_DISCARD_THRESHOLD = "log4j2.*.AsyncLogger.discardThreshold"; + public static final String ASYNC_LOGGER_RING_BUFFER_SIZE = "log4j2.*.AsyncLogger.ringBufferSize"; + public static final String ASYNC_LOGGER_WAIT_STRATEGY = "log4j2.*.AsyncLogger.waitStrategy"; + public static final String ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = "log4j2.*.AsyncLogger.synchronizeEnqueueWhenQueueFull"; + @Deprecated // should use DI bindings + public static final String ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME = "log4j2.*.AsyncLogger.exceptionHandler"; + public static final String ASYNC_LOGGER_THREAD_NAME_STRATEGY = "log4j2.*.AsyncLogger.threadNameStrategy"; + public static final String ASYNC_CONFIG_RING_BUFFER_SIZE = "log4j2.*.AsyncLoggerConfig.ringBufferSize"; + public static final String ASYNC_CONFIG_WAIT_STRATEGY = "log4j2.*.AsyncLoggerConfig.waitStrategy"; + public static final String ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = "log4j2.*.AsyncLoggerConfig.synchronizeEnqueueWhenQueueFull"; + @Deprecated // should use DI bindings + public static final String ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME = "log4j2.*.AsyncLoggerConfig.exceptionHandler"; - // Configuration.level - public static final String CONFIG_DEFAULT_LEVEL = "log4j2.level"; - // Configuration.clock - public static final String CONFIG_CLOCK = "log4j2.clock"; - // Configuration.mergeStrategy - public static final String CONFIG_MERGE_STRATEGY_CLASS_NAME = "log4j2.mergeStrategy"; - // Configuration.reliabilityStrategy - public static final String CONFIG_RELIABILITY_STRATEGY = "log4j2.reliabilityStrategy"; - // Configuration.reliabilityStrategyAwaitUnconditionallyMillis - public static final String CONFIG_RELIABILITY_STRATEGY_AWAIT_UNCONDITIONALLY_MILLIS = "log4j2.waitMillisBeforeStopOldConfig"; - // Configuration.factory - public static final String CONFIG_CONFIGURATION_FACTORY_CLASS_NAME = "log4j2.configurationFactory"; - // Configuration.location - public static final String CONFIG_LOCATION = "log4j2.configurationFile"; - public static final String CONFIG_V1_FILE_NAME = "log4j.configuration"; - public static final String CONFIG_V1_COMPATIBILITY_ENABLED = "log4j1.compatibility"; + public static final String GC_ENABLE_DIRECT_ENCODERS = "log4j2.*.GC.enableDirectEncoders"; + public static final String GC_INITIAL_REUSABLE_MESSAGE_SIZE = "log4j2.*.GC.initialReusableMsgSize"; + public static final String GC_ENCODER_CHAR_BUFFER_SIZE = "log4j2.*.GC.encoderCharBufferSize"; + public static final String GC_ENCODER_BYTE_BUFFER_SIZE = "log4j2.*.GC.encoderByteBufferSize"; + public static final String GC_LAYOUT_STRING_BUILDER_MAX_SIZE = "log4j2.*.GC.layoutStringBuilderMaxSize"; + public static final String GC_USE_PRECISE_CLOCK = "log4j2.*.GC.usePreciseClock"; - // AsyncLogger.formatMsgAsync - public static final String ASYNC_LOGGER_FORMAT_MESSAGES_IN_BACKGROUND = "log4j2.formatMsgAsync"; - // AsyncLogger.queueFullPolicy - public static final String ASYNC_LOGGER_QUEUE_FULL_POLICY = "log4j2.asyncQueueFullPolicy"; - // AsyncLogger.discardThreshold - public static final String ASYNC_LOGGER_DISCARD_THRESHOLD = "log4j2.discardThreshold"; - // AsyncLogger.ringBufferSize - public static final String ASYNC_LOGGER_RING_BUFFER_SIZE = "log4j2.AsyncLogger.ringBufferSize"; - // AsyncLogger.waitStrategy - public static final String ASYNC_LOGGER_WAIT_STRATEGY = "log4j2.AsyncLogger.waitStrategy"; - // AsyncLogger.synchronizeEnqueueWhenQueueFull - public static final String ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = "log4j2.AsyncLogger.synchronizeEnqueueWhenQueueFull"; - // AsyncLogger.exceptionHandler - public static final String ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME = "log4j2.AsyncLogger.exceptionHandler"; - // AsyncLogger.threadNameStrategy - public static final String ASYNC_LOGGER_THREAD_NAME_STRATEGY = "log4j2.AsyncLogger.threadNameStrategy"; - // AsyncLoggerConfig.ringBufferSize - public static final String ASYNC_CONFIG_RING_BUFFER_SIZE = "log4j2.AsyncLoggerConfig.ringBufferSize"; - // AsyncLoggerConfig.waitStrategy - public static final String ASYNC_CONFIG_WAIT_STRATEGY = "log4j2.AsyncLoggerConfig.waitStrategy"; - // AsyncLoggerConfig.synchronizeEnqueueWhenQueueFull - public static final String ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = "log4j2.AsyncLoggerConfig.synchronizeEnqueueWhenQueueFull"; - // AsyncLoggerConfig.exceptionHandler - public static final String ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME = "log4j2.AsyncLoggerConfig.exceptionHandler"; + @Deprecated // should use DI bindings + public static final String THREAD_CONTEXT_DATA_CLASS_NAME = "log4j2.*.ThreadContext.contextData"; - // GC.enableDirectEncoders - public static final String GC_ENABLE_DIRECT_ENCODERS = "log4j2.enableDirectEncoders"; - // GC.initialReusableMsgSize - public static final String GC_INITIAL_REUSABLE_MESSAGE_SIZE = "log4j2.initialReusableMsgSize"; - // GC.encoderCharBufferSize - public static final String GC_ENCODER_CHAR_BUFFER_SIZE = "log4j2.encoderCharBufferSize"; - // GC.encoderByteBufferSize - public static final String GC_ENCODER_BYTE_BUFFER_SIZE = "log4j2.encoderByteBufferSize"; - // GC.layoutStringBuilderMaxSize - public static final String GC_LAYOUT_STRING_BUILDER_MAX_SIZE = "log4j2.layoutStringBuilderMaxSize"; + public static final String JMX_ENABLED = "log4j2.*.JMX.enabled"; + public static final String JMX_NOTIFY_ASYNC = "log4j2.*.JMX.notifyAsync"; - // ThreadContext.contextData - public static final String THREAD_CONTEXT_DATA_CLASS_NAME = "log4j2.contextData"; - // ThreadContext.contextDataInjector - public static final String THREAD_CONTEXT_DATA_INJECTOR_CLASS_NAME = "log4j2.contextDataInjector"; + public static final String TRANSPORT_SECURITY_BASIC_USERNAME = "log4j2.*.TransportSecurity.basicUsername"; + public static final String TRANSPORT_SECURITY_BASIC_PASSWORD = "log4j2.*.TransportSecurity.basicPassword"; - // JMX.enabled - public static final String JMX_DISABLED = "log4j2.disableJmx"; - // JMX.notifyAsync - public static final String JMX_NOTIFY_ASYNC = "log4j2.jmxNotifyAsync"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_LOCATION = "log4j2.*.TransportSecurity.trustStoreLocation"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD = "log4j2.*.TransportSecurity.trustStorePassword"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_FILE = "log4j2.*.TransportSecurity.trustStorePasswordFile"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_ENV_VAR = "log4j2.*.TransportSecurity.trustStorePasswordEnvironmentVariable"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_KEY_STORE_TYPE = "log4j2.*.TransportSecurity.trustStoreKeyStoreType"; + public static final String TRANSPORT_SECURITY_TRUST_STORE_KEY_MANAGER_FACTORY_ALGORITHM = "log4j2.*.TransportSecurity.trustStoreKeyManagerFactoryAlgorithm"; - // TransportSecurity.trustStore.location - public static final String TRANSPORT_SECURITY_TRUST_STORE_LOCATION = "log4j2.trustStoreLocation"; - // TransportSecurity.trustStore.password - public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD = "log4j2.trustStorePassword"; - // TransportSecurity.trustStore.passwordFile - public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_FILE = "log4j2.trustStorePasswordFile"; - // TransportSecurity.trustStore.passwordEnvironmentVariable - public static final String TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_ENV_VAR = "log4j2.trustStorePasswordEnvironmentVariable"; - // TransportSecurity.trustStore.keyStoreType - public static final String TRANSPORT_SECURITY_TRUST_STORE_KEY_STORE_TYPE = "log4j2.trustStoreKeyStoreType"; - // TransportSecurity.trustStore.keyManagerFactoryAlgorithm - public static final String TRANSPORT_SECURITY_TRUST_STORE_KEY_MANAGER_FACTORY_ALGORITHM = "log4j2.trustStoreKeyManagerFactoryAlgorithm"; - // TransportSecurity.keyStore.location - public static final String TRANSPORT_SECURITY_KEY_STORE_LOCATION = "log4j2.keyStoreLocation"; - // TransportSecurity.keyStore.password - public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD = "log4j2.keyStorePassword"; - // TransportSecurity.keyStore.passwordFile - public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD_FILE = "log4j2.keyStorePasswordFile"; - // TransportSecurity.keyStore.passwordEnvironmentVariable - public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD_ENV_VAR = "log4j2.keyStorePasswordEnvironmentVariable"; - // TransportSecurity.keyStore.keyStoreType - public static final String TRANSPORT_SECURITY_KEY_STORE_TYPE = "log4j2.keyStoreType"; - // TransportSecurity.keyStore.keyManagerFactoryAlgorithm - public static final String TRANSPORT_SECURITY_KEY_STORE_KEY_MANAGER_FACTORY_ALGORITHM = "log4j2.keyStoreKeyManagerFactoryAlgorithm"; - // TransportSecurity.verifyHostName - public static final String TRANSPORT_SECURITY_VERIFY_HOST_NAME = "log4j2.sslVerifyHostName"; + public static final String TRANSPORT_SECURITY_KEY_STORE_LOCATION = "log4j2.*.TransportSecurity.keyStoreLocation"; + public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD = "log4j2.*.TransportSecurity.keyStorePassword"; + public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD_FILE = "log4j2.*.TransportSecurity.keyStorePasswordFile"; + public static final String TRANSPORT_SECURITY_KEY_STORE_PASSWORD_ENV_VAR = "log4j2.*.TransportSecurity.keyStorePasswordEnvironmentVariable"; + public static final String TRANSPORT_SECURITY_KEY_STORE_TYPE = "log4j2.*.TransportSecurity.keyStoreType"; + public static final String TRANSPORT_SECURITY_KEY_STORE_KEY_MANAGER_FACTORY_ALGORITHM = "log4j2.*.TransportSecurity.keyStoreKeyManagerFactoryAlgorithm"; + public static final String TRANSPORT_SECURITY_VERIFY_HOST_NAME = "log4j2.*.TransportSecurity.verifyHostName"; /** * Property that may be used to seed the UUID generation with an integer value. * * @see org.apache.logging.log4j.core.util.UuidUtil */ - // UUID.sequence - public static final String UUID_SEQUENCE = "log4j2.uuidSequence"; + public static final String UUID_SEQUENCE = "log4j2.*.UUID.sequence"; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventBuilder.java new file mode 100644 index 00000000000..fbbaf6b5de5 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventBuilder.java @@ -0,0 +1,393 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.impl; + +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; +import org.apache.logging.log4j.core.async.RingBufferLogEvent; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.time.Clock; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.core.time.MutableInstant; +import org.apache.logging.log4j.core.time.internal.SystemClock; +import org.apache.logging.log4j.message.LoggerNameAwareMessage; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.TimestampMessage; +import org.apache.logging.log4j.plugins.util.Builder; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.StringMap; +import org.apache.logging.log4j.util.Strings; + +public class LogEventBuilder implements LogEvent, Builder { + private String loggerFqcn; + private String loggerName = Strings.EMPTY; + private Level level = Level.OFF; + private Marker marker; + private Message message; + private Throwable thrown; + private ThrowableProxy thrownProxy; + private Clock clock; + private final MutableInstant instant = new MutableInstant(); + private ContextDataInjector contextDataInjector; + private ContextDataFactory contextDataFactory; + private StringMap contextData; + private ThreadContext.ContextStack contextStack; + private long threadId; + private String threadName; + private int threadPriority; + private StackTraceElement source; + private boolean includeLocation; + private boolean endOfBatch; + private long nanoTime; + + @Override + public String getLoggerFqcn() { + return loggerFqcn; + } + + public LogEventBuilder setLoggerFqcn(final String loggerFqcn) { + this.loggerFqcn = loggerFqcn; + return this; + } + + @Override + public String getLoggerName() { + return loggerName; + } + + public LogEventBuilder setLoggerName(final String loggerName) { + this.loggerName = loggerName; + return this; + } + + @Override + public Level getLevel() { + if (level == null) { + level = Level.OFF; // LOG4J2-462, LOG4J2-465 + } + return level; + } + + public LogEventBuilder setLevel(final Level level) { + this.level = level; + return this; + } + + @Override + public Marker getMarker() { + return marker; + } + + public LogEventBuilder setMarker(final Marker marker) { + this.marker = marker; + return this; + } + + @Override + public Message getMessage() { + return message; + } + + public LogEventBuilder setMessage(final Message message) { + this.message = message; + return this; + } + + @Override + public Throwable getThrown() { + return thrown; + } + + public LogEventBuilder setThrown(final Throwable thrown) { + this.thrown = thrown; + return this; + } + + @Override + public ThrowableProxy getThrownProxy() { + return thrownProxy; + } + + public LogEventBuilder setThrownProxy(final ThrowableProxy thrownProxy) { + this.thrownProxy = thrownProxy; + return this; + } + + public Clock getClock() { + if (clock == null) { + clock = new SystemClock(); + } + return clock; + } + + public LogEventBuilder setClock(final Clock clock) { + this.clock = clock; + return this; + } + + @Override + public MutableInstant getInstant() { + initTimeFields(); + return instant; + } + + public LogEventBuilder setInstant(final Instant instant) { + this.instant.initFrom(instant); + return this; + } + + @Override + public long getTimeMillis() { + return instant.getEpochMillisecond(); + } + + public LogEventBuilder setTimeMillis(final long millis) { + this.instant.initFromEpochMilli(millis, 0); + return this; + } + + public ContextDataInjector getContextDataInjector() { + if (contextDataInjector == null) { + contextDataInjector = ThreadContextDataInjector.create(getContextDataFactory()); + } + return contextDataInjector; + } + + public LogEventBuilder setContextDataInjector(final ContextDataInjector contextDataInjector) { + this.contextDataInjector = contextDataInjector; + return this; + } + + public ContextDataFactory getContextDataFactory() { + if (contextDataFactory == null) { + contextDataFactory = new DefaultContextDataFactory(); + } + return contextDataFactory; + } + + public LogEventBuilder setContextDataFactory(final ContextDataFactory contextDataFactory) { + this.contextDataFactory = contextDataFactory; + return this; + } + + @Override + public StringMap getContextData() { + if (contextData == null) { + contextData = getContextDataInjector().injectContextData(null, getContextDataFactory().createContextData()); + } + return contextData; + } + + public LogEventBuilder setContextData(final StringMap contextData) { + this.contextData = contextData; + return this; + } + + public LogEventBuilder setContextData(final List properties) { + contextData = getContextDataInjector().injectContextData(properties, getContextDataFactory().createContextData()); + return this; + } + + @Override + public ThreadContext.ContextStack getContextStack() { + if (contextStack == null) { + contextStack = ThreadContext.EMPTY_STACK; + } + return contextStack; + } + + public LogEventBuilder setContextStack(final ThreadContext.ContextStack contextStack) { + this.contextStack = contextStack; + return this; + } + + @Override + public long getThreadId() { + if (threadId == 0) { + threadId = Thread.currentThread().getId(); + } + return threadId; + } + + public LogEventBuilder setThreadId(final long threadId) { + this.threadId = threadId; + return this; + } + + @Override + public String getThreadName() { + if (threadName == null) { + threadName = Thread.currentThread().getName(); + } + return threadName; + } + + public LogEventBuilder setThreadName(final String threadName) { + this.threadName = threadName; + return this; + } + + @Override + public int getThreadPriority() { + if (threadPriority == 0) { + threadPriority = Thread.currentThread().getPriority(); + } + return threadPriority; + } + + public LogEventBuilder setThreadPriority(final int threadPriority) { + this.threadPriority = threadPriority; + return this; + } + + @Override + public StackTraceElement getSource() { + return source; + } + + public LogEventBuilder setSource(final StackTraceElement source) { + this.source = source; + return this; + } + + @Override + public boolean isIncludeLocation() { + return includeLocation; + } + + public LogEventBuilder includeLocation(final boolean includeLocation) { + this.includeLocation = includeLocation; + return this; + } + + @Override + public void setIncludeLocation(final boolean locationRequired) { + this.includeLocation = locationRequired; + } + + public boolean isEndOfBatch() { + return endOfBatch; + } + + public LogEventBuilder endOfBatch(final boolean endOfBatch) { + this.endOfBatch = endOfBatch; + return this; + } + + @Override + public void setEndOfBatch(final boolean endOfBatch) { + this.endOfBatch = endOfBatch; + } + + public long getNanoTime() { + return nanoTime; + } + + public LogEventBuilder setNanoTime(final long nanoTime) { + this.nanoTime = nanoTime; + return this; + } + + public LogEventBuilder copyFrom(final LogEvent other) { + if (other instanceof RingBufferLogEvent) { + ((RingBufferLogEvent) other).initializeBuilder(this); + return this; + } + if (other instanceof MutableLogEvent) { + ((MutableLogEvent) other).initializeBuilder(this); + return this; + } + this.loggerFqcn = other.getLoggerFqcn(); + this.marker = other.getMarker(); + this.level = other.getLevel(); + this.loggerName = other.getLoggerName(); + this.message = other.getMessage(); + this.instant.initFrom(other.getInstant()); + this.thrown = other.getThrown(); + this.contextStack = other.getContextStack(); + this.includeLocation = other.isIncludeLocation(); + this.endOfBatch = other.isEndOfBatch(); + this.nanoTime = other.getNanoTime(); + + // Avoid unnecessarily initializing thrownProxy, threadName and source if possible + if (other instanceof ImmutableLogEvent) { + final ImmutableLogEvent evt = (ImmutableLogEvent) other; + this.contextData = evt.getContextData(); + this.thrownProxy = evt.getThrownProxyOrNull(); + this.source = evt.getSourceOrNull(); + this.threadId = evt.getThreadIdOrZero(); + this.threadName = evt.getThreadNameOrNull(); + this.threadPriority = evt.getThreadPriorityOrZero(); + } else { + final ReadOnlyStringMap contextData = other.getContextData(); + if (contextData instanceof StringMap) { + this.contextData = (StringMap) contextData; + } else { + final StringMap data = this.contextData; + if (data == null) { + this.contextData = getContextDataFactory().createContextData(); + } else { + if (data.isFrozen()) { + this.contextData = getContextDataFactory().createContextData(); + } else { + data.clear(); + } + } + this.contextData.putAll(contextData); + } + this.thrownProxy = other.getThrownProxy(); + this.source = other.getSource(); + this.threadId = other.getThreadId(); + this.threadName = other.getThreadName(); + this.threadPriority = other.getThreadPriority(); + } + return this; + } + + private void initTimeFields() { + if (instant.getEpochMillisecond() == 0) { + if (message instanceof TimestampMessage) { + setTimeMillis(((TimestampMessage) message).getTimestamp()); + } else { + instant.initFrom(getClock()); + } + } + } + + @Override + public LogEvent toImmutable() { + return get(); + } + + @Override + public LogEvent build() { + if (message instanceof LoggerNameAwareMessage) { + ((LoggerNameAwareMessage) message).setLoggerName(loggerName); + } + initTimeFields(); + // thread values should use fields to allow for lazy initialization + return new ImmutableLogEvent(loggerName, marker, loggerFqcn, getLevel(), message, thrown, thrownProxy, + getContextData(), getContextStack(), threadId, threadName, threadPriority, + source, instant, nanoTime, endOfBatch, includeLocation); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java index 3cfcb3d6c94..4d5df9c2d18 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java @@ -16,20 +16,20 @@ */ package org.apache.logging.log4j.core.impl; +import java.util.Arrays; + import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.InternalApi; import org.apache.logging.log4j.util.StringBuilderFormattable; -import java.util.Arrays; - /** - * Consider this class private. - * - * {@link MementoMessage} is intended to be used when we need to make an + * {@code MementoMessage} is intended to be used when we need to make an * immutable copy of a {@link Message} without forgetting the original * {@link Message#getFormat()} and {@link Message#getParameters()} values. * * @since 3.0 */ +@InternalApi public final class MementoMessage implements Message, StringBuilderFormattable { private final String formattedMessage; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index 787a9121755..f2c15d187ea 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -16,20 +16,19 @@ */ package org.apache.logging.log4j.core.impl; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; import java.util.Arrays; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.async.InternalAsyncUtil; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.core.time.NanoClock; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterConsumer; import org.apache.logging.log4j.message.ParameterVisitable; @@ -65,7 +64,7 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi private Object[] parameters; private Throwable thrown; private ThrowableProxy thrownProxy; - private StringMap contextData = ContextDataFactory.createContextData(); + private StringMap contextData; private Marker marker; private String loggerFqcn; private StackTraceElement source; @@ -73,24 +72,28 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi transient boolean reserved = false; public MutableLogEvent() { + this(new DefaultContextDataFactory()); + } + + public MutableLogEvent(final ContextDataFactory contextDataFactory) { // messageText and the parameter array are lazily initialized - this(null, null); + this(contextDataFactory, null, null); } - public MutableLogEvent(final StringBuilder msgText, final Object[] replacementParameters) { + public MutableLogEvent(final ContextDataFactory contextDataFactory, + final StringBuilder msgText, final Object[] replacementParameters) { + contextData = contextDataFactory.createContextData(); this.messageText = msgText; this.parameters = replacementParameters; } @Override - public Log4jLogEvent toImmutable() { - return createMemento(); + public LogEvent toImmutable() { + return copy(); } /** * Initialize the fields of this {@code MutableLogEvent} from another event. - * Similar in purpose and usage as {@link org.apache.logging.log4j.core.impl.Log4jLogEvent.LogEventProxy}, - * but a mutable version. *

    * This method is used on async logger ringbuffer slots holding MutableLogEvent objects in each slot. *

    @@ -150,7 +153,7 @@ public void clear() { // threadName = null; // no need to clear threadName // ensure that excessively long char[] arrays are not kept in memory forever - StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE); + StringBuilders.trimToMaxSize(messageText, GarbageFreeConfiguration.getDefaultConfiguration().getMaxReusableMessageSize()); if (parameters != null) { Arrays.fill(parameters, null); @@ -227,7 +230,7 @@ public void setMessage(final Message msg) { private StringBuilder getMessageTextForWriting() { if (messageText == null) { // Happens the first time messageText is requested - messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE); + messageText = new StringBuilder(GarbageFreeConfiguration.getDefaultConfiguration().getInitialReusableMessageSize()); } messageText.setLength(0); return messageText; @@ -376,7 +379,6 @@ public StackTraceElement getSource() { return source; } - @SuppressWarnings("unchecked") @Override public ReadOnlyStringMap getContextData() { return contextData; @@ -451,50 +453,23 @@ public void setNanoTime(final long nanoTime) { this.nanoTime = nanoTime; } - /** - * Creates a LogEventProxy that can be serialized. - * @return a LogEventProxy. - */ - protected Object writeReplace() { - return new Log4jLogEvent.LogEventProxy(this, this.includeLocation); - } - - private void readObject(final ObjectInputStream stream) throws InvalidObjectException { - throw new InvalidObjectException("Proxy required"); - } - - /** - * Creates and returns a new immutable copy of this {@code MutableLogEvent}. - * If {@link #isIncludeLocation()} is true, this will obtain caller location information. - * - * @return a new immutable copy of the data in this {@code MutableLogEvent} - */ - public Log4jLogEvent createMemento() { - return Log4jLogEvent.deserialize(Log4jLogEvent.serialize(this, includeLocation)); - } - - /** - * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code MutableLogEvent}. - * @param builder the builder whose fields to populate - */ - public void initializeBuilder(final Log4jLogEvent.Builder builder) { - builder.setContextData(contextData) // - .setContextStack(contextStack) // - .setEndOfBatch(endOfBatch) // - .setIncludeLocation(includeLocation) // + public void initializeBuilder(final LogEventBuilder builder) { + builder.setContextData(contextData) + .setContextStack(contextStack) + .endOfBatch(endOfBatch) + .includeLocation(includeLocation) .setLevel(getLevel()) // ensure non-null - .setLoggerFqcn(loggerFqcn) // - .setLoggerName(loggerName) // - .setMarker(marker) // + .setLoggerFqcn(loggerFqcn) + .setLoggerName(loggerName) + .setMarker(marker) .setMessage(memento()) // ensure non-null & immutable - .setNanoTime(nanoTime) // - .setSource(source) // - .setThreadId(threadId) // - .setThreadName(threadName) // - .setThreadPriority(threadPriority) // + .setNanoTime(nanoTime) + .setSource(source) + .setThreadId(threadId) + .setThreadName(threadName) + .setThreadPriority(threadPriority) .setThrown(getThrown()) // may deserialize from thrownProxy .setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy - .setInstant(instant) // - ; + .setInstant(instant); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java index 3020455c06d..4edfc8be93d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java @@ -16,39 +16,47 @@ */ package org.apache.logging.log4j.core.impl; +import java.util.List; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy; +import org.apache.logging.log4j.core.async.ThreadNameCachingStrategyFactory; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.plugins.ContextScoped; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.util.StringMap; -import java.util.List; - /** * Garbage-free LogEventFactory that reuses a single mutable log event. * @since 2.6 */ +@ContextScoped public class ReusableLogEventFactory implements LogEventFactory { - private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create(); - - private static final ThreadLocal mutableLogEventThreadLocal = new ThreadLocal<>(); + // TODO(ms): migrate to Recycler + private final ThreadLocal mutableLogEventThreadLocal = new ThreadLocal<>(); - private final ContextDataInjector injector; + private final ContextDataInjector contextDataInjector; + private final ContextDataFactory contextDataFactory; private final Clock clock; private final NanoClock nanoClock; + private final ThreadNameCachingStrategyFactory factory; @Inject - public ReusableLogEventFactory(final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock) { - this.injector = injector; + public ReusableLogEventFactory( + final ContextDataInjector contextDataInjector, final ContextDataFactory contextDataFactory, + final Clock clock, final NanoClock nanoClock, final ThreadNameCachingStrategyFactory factory) { + this.contextDataInjector = contextDataInjector; + this.contextDataFactory = contextDataFactory; this.clock = clock; this.nanoClock = nanoClock; + this.factory = factory; } /** @@ -99,23 +107,23 @@ public LogEvent createEvent(final String loggerName, final Marker marker, result.initTime(clock, nanoClock); result.setThrown(t); result.setSource(location); - result.setContextData(injector.injectContextData(properties, (StringMap) result.getContextData())); + result.setContextData(contextDataInjector.injectContextData(properties, (StringMap) result.getContextData())); result.setContextStack(ThreadContext.getDepth() == 0 ? ThreadContext.EMPTY_STACK : ThreadContext.cloneStack());// mutable copy - if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) { + if (factory.get() == ThreadNameCachingStrategy.UNCACHED) { result.setThreadName(Thread.currentThread().getName()); // Thread.getName() allocates Objects on each call result.setThreadPriority(Thread.currentThread().getPriority()); } return result; } - private static MutableLogEvent getOrCreateMutableLogEvent() { + private MutableLogEvent getOrCreateMutableLogEvent() { MutableLogEvent result = mutableLogEventThreadLocal.get(); return result == null || result.reserved ? createInstance(result) : result; } - private static MutableLogEvent createInstance(MutableLogEvent existing) { - MutableLogEvent result = new MutableLogEvent(); + private MutableLogEvent createInstance(MutableLogEvent existing) { + MutableLogEvent result = new MutableLogEvent(contextDataFactory); // usually no need to re-initialize thread-specific fields since the event is stored in a ThreadLocal result.setThreadId(Thread.currentThread().getId()); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java index 9fc5dbcee82..2389299bd75 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java @@ -29,6 +29,8 @@ import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.util.ContextDataProvider; +import org.apache.logging.log4j.spi.CopyOnWrite; +import org.apache.logging.log4j.spi.DefaultThreadContextMap; import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.ServiceRegistry; @@ -39,14 +41,13 @@ * {@code ThreadContext} map implementations into a {@code StringMap}. In the case of duplicate keys, * thread context values overwrite configuration {@code Property} values. *

    - * These are the default {@code ContextDataInjector} objects returned by the {@link ContextDataInjectorFactory}. + * These are the default {@code ContextDataInjector} objects returned by the {@link DefaultBundle}. *

    * * @see org.apache.logging.log4j.ThreadContext * @see Property * @see ReadOnlyStringMap * @see ContextDataInjector - * @see ContextDataInjectorFactory * @since 2.7 */ public class ThreadContextDataInjector { @@ -59,15 +60,6 @@ public class ThreadContextDataInjector { private static final List SERVICE_PROVIDERS = getServiceProviders(); - /** - * Previously this method allowed ContextDataProviders to be loaded eagerly, now they - * are loaded when this class is initialized. - * - * @deprecated no-op - */ - @Deprecated - public static void initServiceProviders() {} - private static List getServiceProviders() { final List providers = new ArrayList<>(); final List services = ServiceRegistry.getInstance() @@ -80,6 +72,20 @@ private static List getServiceProviders() { return Collections.unmodifiableList(providers); } + public static ContextDataInjector create(final ContextDataFactory factory) { + final ReadOnlyThreadContextMap threadContextMap = ThreadContext.getThreadContextMap(); + + // note: map may be null (if legacy custom ThreadContextMap was installed by user) + if (threadContextMap instanceof DefaultThreadContextMap || threadContextMap == null) { + // for non StringMap-based context maps + return new ThreadContextDataInjector.ForDefaultThreadContextMap(factory); + } + if (threadContextMap instanceof CopyOnWrite) { + return new ThreadContextDataInjector.ForCopyOnWriteThreadContextMap(factory); + } + return new ThreadContextDataInjector.ForGarbageFreeThreadContextMap(); + } + /** * Default {@code ContextDataInjector} for the legacy {@code Map}-based ThreadContext (which is @@ -90,8 +96,14 @@ private static List getServiceProviders() { public static class ForDefaultThreadContextMap implements ContextDataInjector { private final List providers; + private final ContextDataFactory factory; public ForDefaultThreadContextMap() { + this(new DefaultContextDataFactory()); + } + + public ForDefaultThreadContextMap(final ContextDataFactory factory) { + this.factory = factory; providers = getProviders(); } @@ -124,24 +136,23 @@ public StringMap injectContextData(final List props, final StringMap c if ((props == null || props.isEmpty())) { // this will replace the LogEvent's context data with the returned instance. // NOTE: must mark as frozen or downstream components may attempt to modify (UnsupportedOperationEx) - return copy.isEmpty() ? ContextDataFactory.emptyFrozenContextData() : frozenStringMap(copy); + return copy.isEmpty() ? factory.emptyFrozenContextData() : frozenStringMap(copy); } // If the list of Properties is non-empty we need to combine the properties and the ThreadContext // data. Note that we cannot reuse the specified StringMap: some Loggers may have properties defined // and others not, so the LogEvent's context data may have been replaced with an immutable copy from // the ThreadContext - this will throw an UnsupportedOperationException if we try to modify it. final StringMap result = new JdkMapAdapterStringMap(new HashMap<>(copy)); - for (int i = 0; i < props.size(); i++) { - final Property prop = props.get(i); + props.forEach(prop -> { if (!copy.containsKey(prop.getName())) { result.putValue(prop.getName(), prop.getValue()); } - } + }); result.freeze(); return result; } - private static JdkMapAdapterStringMap frozenStringMap(final Map copy) { + private JdkMapAdapterStringMap frozenStringMap(final Map copy) { final JdkMapAdapterStringMap result = new JdkMapAdapterStringMap(copy); result.freeze(); return result; @@ -155,7 +166,7 @@ public ReadOnlyStringMap rawContextData() { } // note: default ThreadContextMap is null final Map copy = ThreadContext.getImmutableContext(); - return copy.isEmpty() ? ContextDataFactory.emptyFrozenContextData() : new JdkMapAdapterStringMap(copy); + return copy.isEmpty() ? factory.emptyFrozenContextData() : new JdkMapAdapterStringMap(copy); } } @@ -186,9 +197,7 @@ public StringMap injectContextData(final List props, final StringMap r // StringMap. We cannot return the ThreadContext's internal data structure because it may be modified later // and such modifications should not be reflected in the log event. copyProperties(props, reusable); - for (int i = 0; i < providers.size(); ++i) { - reusable.putAll(providers.get(i).supplyStringMap()); - } + providers.forEach(provider -> reusable.putAll(provider.supplyStringMap())); return reusable; } @@ -203,18 +212,24 @@ public ReadOnlyStringMap rawContextData() { * StringMap-based data structure. *

    * If there are no configuration properties, this injector will return the thread context's internal data - * structure. Otherwise the configuration properties are combined with the thread context key-value pairs into the + * structure. Otherwise, the configuration properties are combined with the thread context key-value pairs into the * specified reusable StringMap. */ public static class ForCopyOnWriteThreadContextMap implements ContextDataInjector { private final List providers; + private final ContextDataFactory factory; public ForCopyOnWriteThreadContextMap() { + this(new DefaultContextDataFactory()); + } + + public ForCopyOnWriteThreadContextMap(final ContextDataFactory factory) { + this.factory = factory; this.providers = getProviders(); } /** * If there are no configuration properties, this injector will return the thread context's internal data - * structure. Otherwise the configuration properties are combined with the thread context key-value pairs into the + * structure. Otherwise, the configuration properties are combined with the thread context key-value pairs into the * specified reusable StringMap. * * @param props list of configuration properties, may be {@code null} @@ -239,7 +254,7 @@ public StringMap injectContextData(final List props, final StringMap i // data. Note that we cannot reuse the specified StringMap: some Loggers may have properties defined // and others not, so the LogEvent's context data may have been replaced with an immutable copy from // the ThreadContext - this will throw an UnsupportedOperationException if we try to modify it. - final StringMap result = ContextDataFactory.createContextData(count); + final StringMap result = factory.createContextData(count); copyProperties(props, result); for (final StringMap map : maps) { result.putAll(map); @@ -261,10 +276,7 @@ public ReadOnlyStringMap rawContextData() { */ public static void copyProperties(final List properties, final StringMap result) { if (properties != null) { - for (int i = 0; i < properties.size(); i++) { - final Property prop = properties.get(i); - result.putValue(prop.getName(), prop.getValue()); - } + properties.forEach(property -> result.putValue(property.getName(), property.getValue())); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java index 794a72c0abc..5e53cc460f6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java @@ -16,18 +16,6 @@ */ package org.apache.logging.log4j.core.jmx; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.config.ConfigurationSource; -import org.apache.logging.log4j.core.util.Closer; -import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.Strings; - -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.NotificationBroadcasterSupport; -import javax.management.ObjectName; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.ByteArrayInputStream; @@ -47,6 +35,18 @@ import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicLong; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.ObjectName; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Strings; /** * Implementation of the {@code LoggerContextAdminMBean} interface. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java index 5b782a921ed..e591f658ff1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java @@ -42,9 +42,10 @@ import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.util.Log4jThreadFactory; import org.apache.logging.log4j.spi.LoggerContextFactory; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Constants; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; /** * Creates MBeans to instrument various classes in the log4j class hierarchy. @@ -74,8 +75,11 @@ private Server() { * @see LOG4J2-938 */ private static ExecutorService createExecutor() { - final boolean defaultAsync = !Constants.isWebApp(); - final boolean async = PropertiesUtil.getProperties().getBooleanProperty(Log4jProperties.JMX_NOTIFY_ASYNC, defaultAsync); + final PropertyResolver resolver = LoggingSystem.getPropertyResolver(); + final boolean defaultAsync = !Constants.isWebApp(resolver); + final boolean async = resolver.getString(Log4jProperties.JMX_NOTIFY_ASYNC) + .filter(value -> "calculate".equalsIgnoreCase(value) ? defaultAsync : "true".equalsIgnoreCase(value)) + .isPresent(); return async ? Executors.newFixedThreadPool(1, Log4jThreadFactory.createDaemonThreadFactory(THREAD_NAME_PREFIX)) : null; } @@ -126,7 +130,7 @@ public static String escape(final String name) { } private static boolean isJmxDisabled() { - return PropertiesUtil.getProperties().getBooleanProperty(Log4jProperties.JMX_DISABLED); + return !LoggingSystem.getPropertyResolver().getBoolean(Log4jProperties.JMX_ENABLED, true); } public static void reregisterMBeansAfterReconfigure() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java index 490d5abd958..1c9e34597a7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; +import java.util.Map; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -23,10 +26,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.status.StatusLogger; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; +import org.apache.logging.log4j.util.Cast; /** * Abstract base class for Layouts. @@ -34,7 +34,7 @@ * @param * The Class that the Layout will format the LogEvent into. */ -public abstract class AbstractLayout implements Layout { +public abstract class AbstractLayout implements Layout { /** * Subclasses can extend this abstract Builder. @@ -52,9 +52,8 @@ public abstract static class Builder> { @PluginBuilderAttribute private byte[] header; - @SuppressWarnings("unchecked") public B asBuilder() { - return (B) this; + return Cast.cast(this); } public Configuration getConfiguration() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java index 78c6bef1b35..f95f4e7a2b8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java @@ -23,14 +23,16 @@ import org.apache.logging.log4j.core.StringLayout; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.impl.DefaultLogEventFactory; -import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.impl.LogEventFactory; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.core.util.StringEncoder; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.spi.AbstractLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.Recycler; +import org.apache.logging.log4j.util.RecyclerFactories; +import org.apache.logging.log4j.util.RecyclerFactory; import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.Strings; @@ -54,6 +56,8 @@ public abstract static class Builder> extends AbstractLayou @PluginElement("headerSerializer") private Serializer headerSerializer; + private RecyclerFactory recyclerFactory; + public Charset getCharset() { return charset; } @@ -66,6 +70,16 @@ public Serializer getHeaderSerializer() { return headerSerializer; } + public RecyclerFactory getRecyclerFactory() { + if (recyclerFactory == null) { + final Configuration configuration = getConfiguration(); + recyclerFactory = configuration != null + ? configuration.getInstance(RecyclerFactory.class) + : RecyclerFactories.ofSpec(null); + } + return recyclerFactory; + } + public B setCharset(final Charset charset) { this.charset = charset; return asBuilder(); @@ -81,6 +95,11 @@ public B setHeaderSerializer(final Serializer headerSerializer) { return asBuilder(); } + @Inject + public B setRecyclerFactory(final RecyclerFactory recyclerFactory) { + this.recyclerFactory = recyclerFactory; + return asBuilder(); + } } public interface Serializer extends Serializer2 { @@ -109,42 +128,18 @@ public interface Serializer2 { /** * Default length for new StringBuilder instances: {@value} . */ + // TODO(ms): this could be configurable protected static final int DEFAULT_STRING_BUILDER_SIZE = 1024; protected static final int MAX_STRING_BUILDER_SIZE = Math.max(DEFAULT_STRING_BUILDER_SIZE, - size(Log4jProperties.GC_LAYOUT_STRING_BUILDER_MAX_SIZE, 2 * 1024)); - - private static final ThreadLocal threadLocal = new ThreadLocal<>(); - - /** - * Returns a {@code StringBuilder} that this Layout implementation can use to write the formatted log event to. - * - * @return a {@code StringBuilder} - */ - protected static StringBuilder getStringBuilder() { - if (AbstractLogger.getRecursionDepth() > 1) { // LOG4J2-2368 - // Recursive logging may clobber the cached StringBuilder. - return new StringBuilder(DEFAULT_STRING_BUILDER_SIZE); - } - StringBuilder result = threadLocal.get(); - if (result == null) { - result = new StringBuilder(DEFAULT_STRING_BUILDER_SIZE); - threadLocal.set(result); - } - trimToMaxSize(result); - result.setLength(0); - return result; - } - - private static int size(final String property, final int defaultValue) { - return PropertiesUtil.getProperties().getIntegerProperty(property, defaultValue); - } + GarbageFreeConfiguration.getDefaultConfiguration().getLayoutStringBuilderMaxSize()); protected static void trimToMaxSize(final StringBuilder stringBuilder) { StringBuilders.trimToMaxSize(stringBuilder, MAX_STRING_BUILDER_SIZE); } private Encoder textEncoder; + /** * The charset for the formatted message. */ @@ -154,8 +149,10 @@ protected static void trimToMaxSize(final StringBuilder stringBuilder) { private final Serializer headerSerializer; + private final Recycler recycler; + protected AbstractStringLayout(final Charset charset) { - this(charset, (byte[]) null, (byte[]) null); + this(charset, null, null); } /** @@ -166,11 +163,25 @@ protected AbstractStringLayout(final Charset charset) { * @param footer the footer bytes */ protected AbstractStringLayout(final Charset aCharset, final byte[] header, final byte[] footer) { + this(aCharset, header, footer, null); + } + + protected AbstractStringLayout(final Charset aCharset, final byte[] header, final byte[] footer, + final RecyclerFactory recyclerFactory) { super(null, header, footer); this.headerSerializer = null; this.footerSerializer = null; - this.charset = aCharset == null ? StandardCharsets.UTF_8 : aCharset; - textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null; + this.charset = aCharset != null ? aCharset : StandardCharsets.UTF_8; + final GarbageFreeConfiguration gfConfig = GarbageFreeConfiguration.getDefaultConfiguration(); + textEncoder = gfConfig.isDirectEncodersEnabled() ? new StringBuilderEncoder(charset) : null; + final RecyclerFactory factory = recyclerFactory != null ? recyclerFactory : RecyclerFactories.ofSpec(null); + recycler = factory.create( + () -> new StringBuilder(DEFAULT_STRING_BUILDER_SIZE), + buf -> { + StringBuilders.trimToMaxSize(buf, gfConfig.getLayoutStringBuilderMaxSize()); + buf.setLength(0); + } + ); } /** @@ -183,11 +194,54 @@ protected AbstractStringLayout(final Charset aCharset, final byte[] header, fina */ protected AbstractStringLayout(final Configuration config, final Charset aCharset, final Serializer headerSerializer, final Serializer footerSerializer) { + this(config, aCharset, headerSerializer, footerSerializer, null); + } + + protected AbstractStringLayout(final Configuration config, final Charset aCharset, + final Serializer headerSerializer, final Serializer footerSerializer, + final RecyclerFactory recyclerFactory) { super(config, null, null); this.headerSerializer = headerSerializer; this.footerSerializer = footerSerializer; this.charset = aCharset == null ? StandardCharsets.UTF_8 : aCharset; - textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null; + final GarbageFreeConfiguration gfConfig = config != null + ? config.getInstance(GarbageFreeConfiguration.class) + : GarbageFreeConfiguration.getDefaultConfiguration(); + textEncoder = gfConfig.isDirectEncodersEnabled() + ? new StringBuilderEncoder(charset) + : null; + final RecyclerFactory factory; + if (recyclerFactory != null) { + factory = recyclerFactory; + } else if (config != null) { + factory = config.getInstance(RecyclerFactory.class); + } else { + factory = RecyclerFactories.ofSpec(null); + } + recycler = factory.create( + () -> new StringBuilder(DEFAULT_STRING_BUILDER_SIZE), + buf -> { + StringBuilders.trimToMaxSize(buf, gfConfig.getLayoutStringBuilderMaxSize()); + buf.setLength(0); + } + ); + } + + /** + * Returns a {@code StringBuilder} that this Layout implementation can use to write the formatted log event to. + * + * @return a {@code StringBuilder} + */ + protected StringBuilder getStringBuilder() { + if (AbstractLogger.getRecursionDepth() > 1) { // LOG4J2-2368 + // Recursive logging may clobber the cached StringBuilder. + return new StringBuilder(DEFAULT_STRING_BUILDER_SIZE); + } + return recycler.acquire(); + } + + protected void recycleStringBuilder(final StringBuilder builder) { + recycler.release(builder); } protected byte[] getBytes(final String s) { @@ -235,11 +289,6 @@ public Serializer getHeaderSerializer() { return headerSerializer; } - private DefaultLogEventFactory getLogEventFactory() { - // TODO: inject this - return DefaultLogEventFactory.newInstance(); - } - /** * Returns a {@code Encoder} that this Layout implementation can use for encoding log events. * @@ -266,8 +315,10 @@ protected String serializeToString(final Serializer serializer) { } final LoggerConfig rootLogger = getConfiguration().getRootLogger(); // Using "" for the FQCN, does it matter? - final LogEvent logEvent = getLogEventFactory().createEvent(rootLogger.getName(), null, Strings.EMPTY, - rootLogger.getLevel(), null, null, null); + + final LogEvent logEvent = getConfiguration() + .getInstance(LogEventFactory.class) + .createEvent(rootLogger.getName(), null, Strings.EMPTY, rootLogger.getLevel(), null, null, null); return serializer.toSerializable(logEvent); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java index 610a70ade05..e7f8ed31e1e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java @@ -16,6 +16,20 @@ */ package org.apache.logging.log4j.core.layout; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -41,20 +55,6 @@ import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.TriConsumer; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.GZIPOutputStream; - /** * Lays out events in the Graylog Extended Log Format (GELF) 1.1. *

    @@ -511,8 +511,14 @@ public String getContentType() { @Override public byte[] toByteArray(final LogEvent event) { - final StringBuilder text = toText(event, getStringBuilder(), false); - final byte[] bytes = getBytes(text.toString()); + final StringBuilder buf = getStringBuilder(); + final byte[] bytes; + try { + final StringBuilder text = toText(event, buf, false); + bytes = getBytes(text.toString()); + } finally { + recycleStringBuilder(buf); + } return compressionType != CompressionType.OFF && bytes.length > compressionThreshold ? compress(bytes) : bytes; } @@ -522,9 +528,14 @@ public void encode(final LogEvent event, final ByteBufferDestination destination super.encode(event, destination); return; } - final StringBuilder text = toText(event, getStringBuilder(), true); - final Encoder helper = getStringBuilderEncoder(); - helper.encode(text, destination); + final StringBuilder buf = getStringBuilder(); + try { + final StringBuilder text = toText(event, buf, true); + final Encoder helper = getStringBuilderEncoder(); + helper.encode(text, destination); + } finally { + recycleStringBuilder(buf); + } } @Override @@ -551,8 +562,13 @@ private byte[] compress(final byte[] bytes) { @Override public String toSerializable(final LogEvent event) { - final StringBuilder text = toText(event, getStringBuilder(), false); - return text.toString(); + final StringBuilder buf = getStringBuilder(); + try { + final StringBuilder text = toText(event, buf, false); + return text.toString(); + } finally { + recycleStringBuilder(buf); + } } private StringBuilder toText(final LogEvent event, final StringBuilder builder, final boolean gcFree) { @@ -667,6 +683,7 @@ public ListChecker getChecker() { } } + // TODO(ms): replace with Recycler private static final ThreadLocal messageStringBuilder = new ThreadLocal<>(); private static StringBuilder getMessageStringBuilder() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java index 5d61ee7e2f2..562f37df575 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java @@ -16,18 +16,6 @@ */ package org.apache.logging.log4j.core.layout; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.pattern.DatePatternConverter; -import org.apache.logging.log4j.core.util.Transform; -import org.apache.logging.log4j.plugins.Configurable; -import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginBuilderAttribute; -import org.apache.logging.log4j.plugins.PluginFactory; -import org.apache.logging.log4j.util.Strings; - import java.io.IOException; import java.io.InterruptedIOException; import java.io.LineNumberReader; @@ -40,6 +28,18 @@ import java.util.ArrayList; import java.util.Date; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.pattern.DatePatternConverter; +import org.apache.logging.log4j.core.util.Transform; +import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginFactory; +import org.apache.logging.log4j.util.Strings; + /** * Outputs events as rows in an HTML table on an HTML page. *

    @@ -227,7 +227,9 @@ public String toSerializable(final LogEvent event) { sbuf.append("").append(Strings.LINE_SEPARATOR); } - return sbuf.toString(); + final String result = sbuf.toString(); + recycleStringBuilder(sbuf); + return result; } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java index 5bb9a0aacf9..71c0076eaee 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java @@ -16,15 +16,15 @@ */ package org.apache.logging.log4j.core.layout; -import org.apache.logging.log4j.core.util.Constants; -import org.apache.logging.log4j.status.StatusLogger; - import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.util.Objects; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; +import org.apache.logging.log4j.status.StatusLogger; + /** * Encoder for StringBuilders that locks on the ByteBufferDestination. */ @@ -35,7 +35,7 @@ public class LockingStringBuilderEncoder implements Encoder { private final CharBuffer cachedCharBuffer; public LockingStringBuilderEncoder(final Charset charset) { - this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE); + this(charset, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderCharBufferSize()); } public LockingStringBuilderEncoder(final Charset charset, final int charBufferSize) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java index 8af7ec90379..b39f6c7dcbd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java @@ -26,20 +26,24 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.pattern.FormattingInfo; import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternFormatter; import org.apache.logging.log4j.core.pattern.PatternParser; import org.apache.logging.log4j.core.pattern.RegexReplacement; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.util.Recycler; +import org.apache.logging.log4j.util.RecyclerFactories; +import org.apache.logging.log4j.util.RecyclerFactory; +import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.Strings; /** @@ -89,27 +93,29 @@ public final class PatternLayout extends AbstractStringLayout { /** * Constructs a PatternLayout using the supplied conversion pattern. * - * @param config The Configuration. - * @param replace The regular expression to match. - * @param eventPattern conversion pattern. - * @param patternSelector The PatternSelector. - * @param charset The character set. + * @param config The Configuration. + * @param recyclerFactory the recycler factory to use for StringBuilder instances + * @param replace The regular expression to match. + * @param eventPattern conversion pattern. + * @param patternSelector The PatternSelector. + * @param charset The character set. * @param alwaysWriteExceptions Whether or not exceptions should always be handled in this pattern (if {@code true}, - * exceptions will be written even if the pattern does not specify so). - * @param disableAnsi - * If {@code "true"}, do not output ANSI escape codes - * @param noConsoleNoAnsi - * If {@code "true"} (default) and {@link System#console()} is null, do not output ANSI escape codes - * @param headerPattern header conversion pattern. - * @param footerPattern footer conversion pattern. + * exceptions will be written even if the pattern does not specify so). + * @param disableAnsi If {@code "true"}, do not output ANSI escape codes + * @param noConsoleNoAnsi If {@code "true"} (default) and {@link System#console()} is null, do not output ANSI escape codes + * @param headerPattern header conversion pattern. + * @param footerPattern footer conversion pattern. */ - private PatternLayout(final Configuration config, final RegexReplacement replace, final String eventPattern, - final PatternSelector patternSelector, final Charset charset, final boolean alwaysWriteExceptions, - final boolean disableAnsi, final boolean noConsoleNoAnsi, final String headerPattern, - final String footerPattern) { + private PatternLayout(final Configuration config, final RecyclerFactory recyclerFactory, + final RegexReplacement replace, final String eventPattern, + final PatternSelector patternSelector, final Charset charset, + final boolean alwaysWriteExceptions, final boolean disableAnsi, + final boolean noConsoleNoAnsi, final String headerPattern, + final String footerPattern) { super(config, charset, newSerializerBuilder() .setConfiguration(config) + .setRecyclerFactory(recyclerFactory) .setReplace(replace) .setPatternSelector(patternSelector) .setAlwaysWriteExceptions(alwaysWriteExceptions) @@ -119,6 +125,7 @@ private PatternLayout(final Configuration config, final RegexReplacement replace .build(), newSerializerBuilder() .setConfiguration(config) + .setRecyclerFactory(recyclerFactory) .setReplace(replace) .setPatternSelector(patternSelector) .setAlwaysWriteExceptions(alwaysWriteExceptions) @@ -130,6 +137,7 @@ private PatternLayout(final Configuration config, final RegexReplacement replace this.patternSelector = patternSelector; this.eventSerializer = newSerializerBuilder() .setConfiguration(config) + .setRecyclerFactory(recyclerFactory) .setReplace(replace) .setPatternSelector(patternSelector) .setAlwaysWriteExceptions(alwaysWriteExceptions) @@ -170,11 +178,10 @@ public String getConversionPattern() { */ @Override public Map getContentFormat() { - final Map result = new HashMap<>(); - result.put("structured", "false"); - result.put("formatType", "conversion"); - result.put("format", conversionPattern); - return result; + return Map.of( + "structured", "false", + "formatType", "conversion", + "format", conversionPattern); } /** @@ -194,10 +201,14 @@ public void serialize(final LogEvent event, final StringBuilder stringBuilder) { @Override public void encode(final LogEvent event, final ByteBufferDestination destination) { - final StringBuilder text = toText(eventSerializer, event, getStringBuilder()); - final Encoder encoder = getStringBuilderEncoder(); - encoder.encode(text, destination); - trimToMaxSize(text); + final StringBuilder buf = getStringBuilder(); + try { + final StringBuilder text = toText(eventSerializer, event, buf); + final Encoder encoder = getStringBuilderEncoder(); + encoder.encode(text, destination); + } finally { + recycleStringBuilder(buf); + } } /** @@ -239,9 +250,11 @@ private interface PatternSerializer extends Serializer, Serializer2 {} private static final class NoFormatPatternSerializer implements PatternSerializer { + private final Recycler recycler; private final LogEventPatternConverter[] converters; - private NoFormatPatternSerializer(final PatternFormatter[] formatters) { + private NoFormatPatternSerializer(final Recycler recycler, final PatternFormatter[] formatters) { + this.recycler = recycler; this.converters = new LogEventPatternConverter[formatters.length]; for (int i = 0; i < formatters.length; i++) { converters[i] = formatters[i].getConverter(); @@ -250,11 +263,11 @@ private NoFormatPatternSerializer(final PatternFormatter[] formatters) { @Override public String toSerializable(final LogEvent event) { - final StringBuilder sb = getStringBuilder(); + final StringBuilder sb = recycler.acquire(); try { return toSerializable(event, sb).toString(); } finally { - trimToMaxSize(sb); + recycler.release(sb); } } @@ -284,19 +297,21 @@ public String toString() { private static final class PatternFormatterPatternSerializer implements PatternSerializer { + private final Recycler recycler; private final PatternFormatter[] formatters; - private PatternFormatterPatternSerializer(final PatternFormatter[] formatters) { + private PatternFormatterPatternSerializer(final Recycler recycler, final PatternFormatter[] formatters) { + this.recycler = recycler; this.formatters = formatters; } @Override public String toSerializable(final LogEvent event) { - final StringBuilder sb = getStringBuilder(); + final StringBuilder sb = recycler.acquire(); try { return toSerializable(event, sb).toString(); } finally { - trimToMaxSize(sb); + recycler.release(sb); } } @@ -319,21 +334,25 @@ public String toString() { private static final class PatternSerializerWithReplacement implements Serializer, Serializer2 { + private final Recycler recycler; private final PatternSerializer delegate; private final RegexReplacement replace; - private PatternSerializerWithReplacement(final PatternSerializer delegate, final RegexReplacement replace) { + private PatternSerializerWithReplacement(final Recycler recycler, + final PatternSerializer delegate, + final RegexReplacement replace) { + this.recycler = recycler; this.delegate = delegate; this.replace = replace; } @Override public String toSerializable(final LogEvent event) { - final StringBuilder sb = getStringBuilder(); + final StringBuilder sb = recycler.acquire(); try { return toSerializable(event, sb).toString(); } finally { - trimToMaxSize(sb); + recycler.release(sb); } } @@ -368,6 +387,7 @@ public boolean requiresLocation() { public static class SerializerBuilder implements org.apache.logging.log4j.plugins.util.Builder { private Configuration configuration; + private RecyclerFactory recyclerFactory; private RegexReplacement replace; private String pattern; private String defaultPattern; @@ -381,6 +401,21 @@ public Serializer build() { if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) { return null; } + if (recyclerFactory == null) { + recyclerFactory = configuration != null + ? configuration.getInstance(RecyclerFactory.class) + : RecyclerFactories.ofSpec(null); + } + final GarbageFreeConfiguration gfConfig = configuration != null + ? configuration.getInstance(GarbageFreeConfiguration.class) + : GarbageFreeConfiguration.getDefaultConfiguration(); + final Recycler recycler = recyclerFactory.create( + () -> new StringBuilder(DEFAULT_STRING_BUILDER_SIZE), + buf -> { + StringBuilders.trimToMaxSize(buf, gfConfig.getLayoutStringBuilderMaxSize()); + buf.setLength(0); + } + ); if (patternSelector == null) { try { final PatternParser parser = createPatternParser(configuration); @@ -396,14 +431,14 @@ public Serializer build() { } } PatternSerializer serializer = hasFormattingInfo - ? new PatternFormatterPatternSerializer(formatters) - : new NoFormatPatternSerializer(formatters); - return replace == null ? serializer : new PatternSerializerWithReplacement(serializer, replace); + ? new PatternFormatterPatternSerializer(recycler, formatters) + : new NoFormatPatternSerializer(recycler, formatters); + return replace == null ? serializer : new PatternSerializerWithReplacement(recycler, serializer, replace); } catch (final RuntimeException ex) { throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex); } } - return new PatternSelectorSerializer(patternSelector, replace); + return new PatternSelectorSerializer(recycler, patternSelector, replace); } public SerializerBuilder setConfiguration(final Configuration configuration) { @@ -411,6 +446,11 @@ public SerializerBuilder setConfiguration(final Configuration configuration) { return this; } + public SerializerBuilder setRecyclerFactory(final RecyclerFactory recyclerFactory) { + this.recyclerFactory = recyclerFactory; + return this; + } + public SerializerBuilder setReplace(final RegexReplacement replace) { this.replace = replace; return this; @@ -450,22 +490,26 @@ public SerializerBuilder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) { private static final class PatternSelectorSerializer implements Serializer, Serializer2 { + private final Recycler recycler; private final PatternSelector patternSelector; private final RegexReplacement replace; - private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) { + private PatternSelectorSerializer(final Recycler recycler, + final PatternSelector patternSelector, + final RegexReplacement replace) { super(); + this.recycler = recycler; this.patternSelector = patternSelector; this.replace = replace; } @Override public String toSerializable(final LogEvent event) { - final StringBuilder sb = getStringBuilder(); + final StringBuilder sb = recycler.acquire(); try { return toSerializable(event, sb).toString(); } finally { - trimToMaxSize(sb); + recycler.release(sb); } } @@ -490,28 +534,10 @@ public boolean requiresLocation() { @Override public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(super.toString()); - builder.append("[patternSelector="); - builder.append(patternSelector); - builder.append(", replace="); - builder.append(replace); - builder.append("]"); - return builder.toString(); + return super.toString() + "[patternSelector=" + patternSelector + ", replace=" + replace + "]"; } } - /** - * Creates a PatternLayout using the default options. These options include using UTF-8, the default conversion - * pattern, exceptions being written, and with ANSI escape codes. - * - * @return the PatternLayout. - * @see #DEFAULT_CONVERSION_PATTERN Default conversion pattern - */ - public static PatternLayout createDefaultLayout() { - return newBuilder().build(); - } - /** * Creates a PatternLayout using the default options and the given configuration. These options include using UTF-8, * the default conversion pattern, exceptions being written, and with ANSI escape codes. @@ -546,9 +572,10 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui @PluginElement("PatternSelector") private PatternSelector patternSelector; - @PluginConfiguration private Configuration configuration; + private RecyclerFactory recyclerFactory; + @PluginElement("Replace") private RegexReplacement regexReplacement; @@ -560,7 +587,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private boolean alwaysWriteExceptions = true; @PluginBuilderAttribute - private boolean disableAnsi = !useAnsiEscapeCodes(); + private Boolean disableAnsi; @PluginBuilderAttribute private boolean noConsoleNoAnsi; @@ -574,11 +601,19 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private Builder() { } - private boolean useAnsiEscapeCodes() { - final PropertyEnvironment properties = PropertiesUtil.getProperties(); - final boolean isPlatformSupportsAnsi = !properties.isOsWindows(); - final boolean isJansiRequested = !properties.getBooleanProperty(Log4jProperties.JANSI_DISABLED, true); - return isPlatformSupportsAnsi || isJansiRequested; + private Configuration getConfiguration() { + if (configuration == null) { + configuration = new DefaultConfiguration(); + } + return configuration; + } + + private boolean isDisableAnsi() { + if (disableAnsi != null) { + return disableAnsi; + } + final boolean enableJansi = getConfiguration().getPropertyResolver().getBoolean(Log4jProperties.JANSI_ENABLED); + return !enableJansi && Constants.isWindows(); } /** @@ -603,11 +638,19 @@ public Builder setPatternSelector(final PatternSelector patternSelector) { * @param configuration * The Configuration. Some Converters require access to the Interpolator. */ + @Inject public Builder setConfiguration(final Configuration configuration) { this.configuration = configuration; return this; } + + @Inject + public Builder setRecyclerFactory(final RecyclerFactory recyclerFactory) { + this.recyclerFactory = recyclerFactory; + return this; + } + /** * @param regexReplacement * A Regex replacement @@ -640,7 +683,7 @@ public Builder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { /** * @param disableAnsi - * If {@code "true"} (default is value of system property `log4j.skipJansi`, or `true` if undefined), + * If {@code "true"} (default is the opposite value of system property {@value Log4jProperties#JANSI_ENABLED}, or `true` if undefined), * do not output ANSI escape codes */ public Builder setDisableAnsi(final boolean disableAnsi) { @@ -677,12 +720,12 @@ public Builder setFooter(final String footer) { @Override public PatternLayout build() { - // fall back to DefaultConfiguration - if (configuration == null) { - configuration = new DefaultConfiguration(); + final Configuration config = getConfiguration(); + if (recyclerFactory == null) { + recyclerFactory = config.getInstance(RecyclerFactory.class); } - return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset, - alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi, header, footer); + return new PatternLayout(config, recyclerFactory, regexReplacement, pattern, patternSelector, + charset, alwaysWriteExceptions, isDisableAnsi(), noConsoleNoAnsi, header, footer); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java index 9af331634f9..0253bb5352b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java @@ -23,7 +23,7 @@ import java.nio.charset.CodingErrorAction; import java.util.Objects; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.status.StatusLogger; /** @@ -48,7 +48,7 @@ public class StringBuilderEncoder implements Encoder { private final int byteBufferSize; public StringBuilderEncoder(final Charset charset) { - this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE, Constants.ENCODER_BYTE_BUFFER_SIZE); + this(charset, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderCharBufferSize(), GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } public StringBuilderEncoder(final Charset charset, final int charBufferSize, final int byteBufferSize) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java index 78b40c1ea24..5f53b9d99ac 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java @@ -16,23 +16,30 @@ */ package org.apache.logging.log4j.core.lookup; +import java.util.function.Supplier; + import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.util.ReadOnlyStringMap; /** * Looks up keys from the context. By default this is the {@link ThreadContext}, but users may - * {@linkplain ContextDataInjectorFactory configure} a custom {@link ContextDataInjector} which obtains context data + * {@linkplain ContextDataInjector configure} a custom {@link ContextDataInjector} which obtains context data * from some other source. */ @Lookup @Plugin("ctx") public class ContextMapLookup implements StrLookup { - private final ContextDataInjector injector = ContextDataInjectorFactory.createInjector(); + private final Supplier injectorSupplier; + + @Inject + public ContextMapLookup(final Supplier injectorSupplier) { + this.injectorSupplier = injectorSupplier; + } /** * Looks up the value from the ThreadContext Map. @@ -45,7 +52,7 @@ public String lookup(final String key) { } private ReadOnlyStringMap currentContextData() { - return injector.rawContextData(); + return injectorSupplier.get().rawContextData(); } /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java index 3700fe193c0..8fbb01236f7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java @@ -14,9 +14,25 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.lookup; -public interface InterpolatorFactory { - Interpolator newInterpolator(final StrLookup defaultLookup); +import java.util.Map; +import java.util.function.Supplier; + +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.plugins.Namespace; + +@ContextScoped +public class InterpolatorFactory { + private final Map> strLookupPlugins; + + @Inject + public InterpolatorFactory(@Namespace(StrLookup.CATEGORY) final Map> strLookupPlugins) { + this.strLookupPlugins = strLookupPlugins; + } + + public Interpolator newInterpolator(final StrLookup defaultLookup) { + return new Interpolator(defaultLookup, strLookupPlugins); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java index 6802123ba4b..46ef660b311 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java @@ -28,6 +28,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationAware; +import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; @@ -1517,6 +1518,7 @@ public String toString() { } @Override + @Inject public void setConfiguration(final Configuration configuration) { this.configuration = configuration; if (this.variableResolver instanceof ConfigurationAware) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java index 253143e5e6e..86668c6dfb1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.net; import java.io.OutputStream; -import java.io.Serializable; import java.net.InetAddress; import java.util.HashMap; import java.util.Map; @@ -56,7 +55,7 @@ public abstract class AbstractSocketManager extends OutputStreamManager { * @param bufferSize The buffer size. */ public AbstractSocketManager(final String name, final OutputStream os, final InetAddress inetAddress, - final String host, final int port, final Layout layout, final boolean writeHeader, + final String host, final int port, final Layout layout, final boolean writeHeader, final int bufferSize) { super(os, name, layout, writeHeader, bufferSize); this.inetAddress = inetAddress; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java index d169ab78d87..907fc93e479 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.net; import java.io.OutputStream; -import java.io.Serializable; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; @@ -45,7 +44,7 @@ public class DatagramSocketManager extends AbstractSocketManager { * @param bufferSize The buffer size */ protected DatagramSocketManager(final String name, final OutputStream os, final InetAddress inetAddress, final String host, - final int port, final Layout layout, final int bufferSize) { + final int port, final Layout layout, final int bufferSize) { super(name, os, inetAddress, host, port, layout, true, bufferSize); } @@ -58,7 +57,7 @@ protected DatagramSocketManager(final String name, final OutputStream os, final * @return A DatagramSocketManager. */ public static DatagramSocketManager getSocketManager(final String host, final int port, - final Layout layout, final int bufferSize) { + final Layout layout, final int bufferSize) { if (Strings.isEmpty(host)) { throw new IllegalArgumentException("A host name is required"); } @@ -92,10 +91,10 @@ public Map getContentFormat() { private static class FactoryData { private final String host; private final int port; - private final Layout layout; + private final Layout layout; private final int bufferSize; - public FactoryData(final String host, final int port, final Layout layout, final int bufferSize) { + public FactoryData(final String host, final int port, final Layout layout, final int bufferSize) { this.host = host; this.port = port; this.layout = layout; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java index 721a423c4a1..5a9bc34f112 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java @@ -18,12 +18,10 @@ import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.util.List; - import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -57,7 +55,7 @@ public class SslSocketManager extends TcpSocketManager { public SslSocketManager(final String name, final OutputStream os, final Socket sock, final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port, final int connectTimeoutMillis, final int reconnectionDelayMillis, final boolean immediateFail, - final Layout layout, final int bufferSize, final SocketOptions socketOptions) { + final Layout layout, final int bufferSize, final SocketOptions socketOptions) { super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, layout, bufferSize, socketOptions); this.sslConfig = sslConfig; } @@ -67,7 +65,7 @@ private static class SslFactoryData extends FactoryData { public SslFactoryData(final SslConfiguration sslConfiguration, final String host, final int port, final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail, - final Layout layout, final int bufferSize, final SocketOptions socketOptions) { + final Layout layout, final int bufferSize, final SocketOptions socketOptions) { super(host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, socketOptions); this.sslConfiguration = sslConfiguration; @@ -84,7 +82,7 @@ public String toString() { public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port, final int connectTimeoutMillis, int reconnectDelayMillis, final boolean immediateFail, - final Layout layout, final int bufferSize, final SocketOptions socketOptions) { + final Layout layout, final int bufferSize, final SocketOptions socketOptions) { if (Strings.isEmpty(host)) { throw new IllegalArgumentException("A host name is required"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java index 6698c1ed176..111cf272f78 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -36,7 +35,7 @@ import org.apache.logging.log4j.core.appender.OutputStreamManager; import org.apache.logging.log4j.core.util.Closer; import org.apache.logging.log4j.core.util.Log4jThread; -import org.apache.logging.log4j.core.util.NullOutputStream; +import org.apache.logging.log4j.util.Cast; import org.apache.logging.log4j.util.Strings; /** @@ -96,7 +95,7 @@ public class TcpSocketManager extends AbstractSocketManager { */ public TcpSocketManager(final String name, final OutputStream os, final Socket socket, final InetAddress inetAddress, final String host, final int port, final int connectTimeoutMillis, - final int reconnectionDelayMillis, final boolean immediateFail, final Layout layout, + final int reconnectionDelayMillis, final boolean immediateFail, final Layout layout, final int bufferSize, final SocketOptions socketOptions) { super(name, os, inetAddress, host, port, layout, true, bufferSize); this.connectTimeoutMillis = connectTimeoutMillis; @@ -127,7 +126,7 @@ public TcpSocketManager(final String name, final OutputStream os, final Socket s * @return A TcpSocketManager. */ public static TcpSocketManager getSocketManager(final String host, int port, final int connectTimeoutMillis, - int reconnectDelayMillis, final boolean immediateFail, final Layout layout, + int reconnectDelayMillis, final boolean immediateFail, final Layout layout, final int bufferSize, final SocketOptions socketOptions) { if (Strings.isEmpty(host)) { throw new IllegalArgumentException("A host name is required"); @@ -363,13 +362,13 @@ static class FactoryData { protected final int connectTimeoutMillis; protected final int reconnectDelayMillis; protected final boolean immediateFail; - protected final Layout layout; + protected final Layout layout; protected final int bufferSize; protected final SocketOptions socketOptions; public FactoryData(final String host, final int port, final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail, - final Layout layout, final int bufferSize, final SocketOptions socketOptions) { + final Layout layout, final int bufferSize, final SocketOptions socketOptions) { this.host = host; this.port = port; this.connectTimeoutMillis = connectTimeoutMillis; @@ -420,7 +419,7 @@ public M createManager(final String name, final T data) { return createManager(name, os, socket, inetAddress, data); } catch (final IOException ex) { LOGGER.error("TcpSocketManager ({}) caught exception and will continue:", name, ex); - os = NullOutputStream.getInstance(); + os = OutputStream.nullOutputStream(); } if (data.reconnectDelayMillis == 0) { Closer.closeSilently(socket); @@ -429,11 +428,10 @@ public M createManager(final String name, final T data) { return createManager(name, os, null, inetAddress, data); } - @SuppressWarnings("unchecked") M createManager(final String name, final OutputStream os, final Socket socket, final InetAddress inetAddress, final T data) { - return (M) new TcpSocketManager(name, os, socket, inetAddress, data.host, data.port, + return Cast.cast(new TcpSocketManager(name, os, socket, inetAddress, data.host, data.port, data.connectTimeoutMillis, data.reconnectDelayMillis, data.immediateFail, data.layout, - data.bufferSize, data.socketOptions); + data.bufferSize, data.socketOptions)); } Socket createSocket(final T data) throws IOException { @@ -480,7 +478,7 @@ public static void setHostResolver(HostResolver resolver) { } public static class HostResolver { - + /** * Singleton instance. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java index 445cfe356ca..04a04b5ecd6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java @@ -22,26 +22,29 @@ import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; -import java.util.Arrays; import java.util.List; -import java.util.Locale; +import java.util.concurrent.TimeUnit; import javax.net.ssl.HttpsURLConnection; -import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; import org.apache.logging.log4j.core.util.AuthorizationProvider; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; -import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.util.Cast; +import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.PropertyResolver; /** * Constructs an HTTPURLConnection. This class should be considered to be internal */ +@InternalApi +@ContextScoped public class UrlConnectionFactory { - private static final int DEFAULT_TIMEOUT = 60000; + private static final int DEFAULT_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(1); private static final int connectTimeoutMillis = DEFAULT_TIMEOUT; private static final int readTimeoutMillis = DEFAULT_TIMEOUT; private static final String JSON = "application/json"; @@ -51,17 +54,28 @@ public class UrlConnectionFactory { private static final String HTTP = "http"; private static final String HTTPS = "https"; private static final String JAR = "jar"; - private static final String DEFAULT_ALLOWED_PROTOCOLS = "https, file, jar"; + private static final List DEFAULT_ALLOWED_PROTOCOLS = List.of("https", "file", "jar"); private static final String NO_PROTOCOLS = "_none"; - public static final String ALLOWED_PROTOCOLS = "log4j2.Configuration.allowedProtocols"; + public static final String ALLOWED_PROTOCOLS = Log4jProperties.CONFIG_ALLOWED_PROTOCOLS; - @SuppressWarnings("unchecked") - public static T createConnection(final URL url, final long lastModifiedMillis, - final SslConfiguration sslConfiguration, final AuthorizationProvider authorizationProvider) - throws IOException { - final PropertyEnvironment props = PropertiesUtil.getProperties(); - final List allowed = Arrays.asList(Strings.splitList(props - .getStringProperty(ALLOWED_PROTOCOLS, DEFAULT_ALLOWED_PROTOCOLS).toLowerCase(Locale.ROOT))); + private final PropertyResolver propertyResolver; + private final AuthorizationProvider authorizationProvider; + private final SslConfigurationFactory sslConfigurationFactory; + + @Inject + public UrlConnectionFactory(final PropertyResolver propertyResolver, + final AuthorizationProvider authorizationProvider, + final SslConfigurationFactory sslConfigurationFactory) { + this.propertyResolver = propertyResolver; + this.authorizationProvider = authorizationProvider; + this.sslConfigurationFactory = sslConfigurationFactory; + } + + public T openConnection(final URL url, final long lastModifiedMillis) throws IOException { + List allowed = propertyResolver.getList(Log4jProperties.CONFIG_ALLOWED_PROTOCOLS); + if (allowed.isEmpty()) { + allowed = DEFAULT_ALLOWED_PROTOCOLS; + } if (allowed.size() == 1 && NO_PROTOCOLS.equals(allowed.get(0))) { throw new ProtocolException("No external protocols have been enabled"); } @@ -95,6 +109,7 @@ public static T createConnection(final URL url, final if (lastModifiedMillis > 0) { httpURLConnection.setIfModifiedSince(lastModifiedMillis); } + final SslConfiguration sslConfiguration = sslConfigurationFactory.get(); if (url.getProtocol().equals(HTTPS) && sslConfiguration != null) { ((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory()); if (!sslConfiguration.isVerifyHostName()) { @@ -108,14 +123,13 @@ public static T createConnection(final URL url, final } else { urlConnection = url.openConnection(); } - return (T) urlConnection; + return Cast.cast(urlConnection); } - public static URLConnection createConnection(final URL url) throws IOException { - URLConnection urlConnection = null; + public URLConnection openConnection(final URL url) throws IOException { + final URLConnection urlConnection; if (url.getProtocol().equals(HTTPS) || url.getProtocol().equals(HTTP)) { - final AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties()); - urlConnection = createConnection(url, 0, SslConfigurationFactory.getSslConfiguration(), provider); + urlConnection = openConnection(url, 0); } else { urlConnection = url.openConnection(); if (urlConnection instanceof JarURLConnection) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java index 4df86e7f8c4..f7d4efee52e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java @@ -16,17 +16,27 @@ */ package org.apache.logging.log4j.core.net.ssl; +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.JarURLConnection; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.NoSuchFileException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.util.Arrays; -import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.NetUtils; +import org.apache.logging.log4j.plugins.PluginAttribute; /** * Configuration of the KeyStore @@ -84,7 +94,32 @@ protected KeyStore load() throws StoreConfigurationException { } private InputStream openInputStream(final String filePathOrUri) { - return ConfigurationSource.fromUri(NetUtils.toURI(filePathOrUri)).getInputStream(); + // to avoid a circular dependency between SslConfigurationFactory and UrlConnectionFactory, we replicate + // some of essential logic without supporting more specific ssl configuration as this is part of the ssl + // configuration in the first place + final URI uri = NetUtils.toURI(filePathOrUri); + try { + final File file = FileUtils.fileFromUri(uri); + if (file != null) { + return new FileInputStream(file); + } + } catch (final FileNotFoundException e) { + LOGGER.warn("Cannot locate file {}", filePathOrUri); + } + final String scheme = uri.getScheme(); + if (scheme == null || "classpath".equals(scheme) || "classloader".equals(scheme)) { + final String resource = scheme == null ? uri.getPath() : uri.getSchemeSpecificPart(); + return Loader.getResourceAsStream(resource, null); + } + try { + final URL url = uri.toURL(); + final URLConnection urlConnection = url.openConnection(); + // A "jar:" URL file remains open after the stream is closed, so do not cache it. + urlConnection.setUseCaches(false); + return urlConnection.getInputStream(); + } catch (final IOException e) { + throw new UncheckedIOException("Cannot load file path or URI: " + filePathOrUri, e); + } } public KeyStore getKeyStore() { @@ -133,4 +168,42 @@ public String getKeyStoreType() { return keyStoreType; } + public static abstract class Builder, C extends AbstractKeyStoreConfiguration> + extends StoreConfiguration.Builder { + private String type; + + public String getKeyStoreType() { + return type; + } + + public B setKeyStoreType(@PluginAttribute final String type) { + this.type = type; + return asBuilder(); + } + + protected PasswordProvider buildPasswordProvider() throws StoreConfigurationException { + final char[] password = getPassword(); + final String passwordEnvironmentVariable = getPasswordEnvironmentVariable(); + final String passwordFile = getPasswordFile(); + if (password != null && passwordEnvironmentVariable != null && passwordFile != null) { + throw new StoreConfigurationException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'."); + } + final PasswordProvider passwordProvider; + if (passwordFile != null) { + try { + return new FilePasswordProvider(passwordFile); + } catch (final NoSuchFileException e) { + throw new StoreConfigurationException("Unable to configure TrustStore with password file", e); + } + } else if (passwordEnvironmentVariable != null) { + passwordProvider = new EnvironmentPasswordProvider(passwordEnvironmentVariable); + } else { + passwordProvider = new MemoryPasswordProvider(password); + } + if (password != null) { + Arrays.fill(password, '\0'); + } + return passwordProvider; + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java index 3a3296a9a95..ffe6e65d99c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java @@ -16,16 +16,16 @@ */ package org.apache.logging.log4j.core.net.ssl; -import org.apache.logging.log4j.plugins.Configurable; -import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginAttribute; -import org.apache.logging.log4j.plugins.PluginFactory; - -import javax.net.ssl.KeyManagerFactory; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.util.Arrays; +import javax.net.ssl.KeyManagerFactory; + +import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginAttribute; +import org.apache.logging.log4j.plugins.PluginFactory; /** * Configuration of the KeyStore @@ -40,89 +40,16 @@ public class KeyStoreConfiguration extends AbstractKeyStoreConfiguration { * * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore. */ - public KeyStoreConfiguration(final String location, - final PasswordProvider passwordProvider, - final String keyStoreType, - final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { + private KeyStoreConfiguration(final String location, + final PasswordProvider passwordProvider, + final String keyStoreType, + final String keyManagerFactoryAlgorithm) + throws StoreConfigurationException { super(location, passwordProvider, keyStoreType); this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : keyManagerFactoryAlgorithm; } - /** - * - * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore. - * @deprecated use {@link #KeyStoreConfiguration(String, PasswordProvider, String, String)} instead - */ - @Deprecated - public KeyStoreConfiguration(final String location, - final char[] password, - final String keyStoreType, - final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { - this(location, new MemoryPasswordProvider(password), keyStoreType, keyManagerFactoryAlgorithm); - if (password != null) { - Arrays.fill(password, '\0'); - } - } - - /** - * - * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore. - * @deprecated Use {@link #KeyStoreConfiguration(String, PasswordProvider, String, String)} instead - */ - @Deprecated - public KeyStoreConfiguration(final String location, final String password, final String keyStoreType, - final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { - this(location, new MemoryPasswordProvider(password == null ? null : password.toCharArray()), keyStoreType, - keyManagerFactoryAlgorithm); - } - - /** - * Creates a KeyStoreConfiguration. - * - * @param location - * The location of the KeyStore, a file path, URL or resource. - * @param password - * The password to access the KeyStore. - * @param keyStoreType - * The KeyStore type, null defaults to {@code "JKS"}. - * @param keyManagerFactoryAlgorithm - * The standard name of the requested algorithm. See the Java Secure Socket Extension Reference Guide for information about these names. - * @return a new KeyStoreConfiguration - * @throws StoreConfigurationException Thrown if this call cannot load the KeyStore. - */ - @PluginFactory - public static KeyStoreConfiguration createKeyStoreConfiguration( - // @formatter:off - @PluginAttribute final String location, - @PluginAttribute(sensitive = true) final char[] password, - @PluginAttribute final String passwordEnvironmentVariable, - @PluginAttribute final String passwordFile, - @PluginAttribute("type") final String keyStoreType, - @PluginAttribute final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { - // @formatter:on - - if (password != null && passwordEnvironmentVariable != null && passwordFile != null) { - throw new StoreConfigurationException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'."); - } - try { - // @formatter:off - final PasswordProvider provider = passwordFile != null - ? new FilePasswordProvider(passwordFile) - : passwordEnvironmentVariable != null - ? new EnvironmentPasswordProvider(passwordEnvironmentVariable) - // the default is memory char[] array, which may be null - : new MemoryPasswordProvider(password); - // @formatter:on - if (password != null) { - Arrays.fill(password, '\0'); - } - return new KeyStoreConfiguration(location, provider, keyStoreType, keyManagerFactoryAlgorithm); - } catch (final Exception ex) { - throw new StoreConfigurationException("Could not configure KeyStore", ex); - } - } - public KeyManagerFactory initKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { final KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(this.keyManagerFactoryAlgorithm); @@ -170,4 +97,28 @@ public boolean equals(final Object obj) { public String getKeyManagerFactoryAlgorithm() { return keyManagerFactoryAlgorithm; } + + @PluginFactory + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractKeyStoreConfiguration.Builder { + private String keyManagerFactoryAlgorithm; + + public String getKeyManagerFactoryAlgorithm() { + return keyManagerFactoryAlgorithm; + } + + public Builder setKeyManagerFactoryAlgorithm(@PluginAttribute final String keyManagerFactoryAlgorithm) { + this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm; + return this; + } + + @Override + public KeyStoreConfiguration build() throws StoreConfigurationException { + return new KeyStoreConfiguration(getLocation(), buildPasswordProvider(), getKeyStoreType(), + getKeyManagerFactoryAlgorithm()); + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java index ff928168679..88e5ee5f5fe 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java @@ -16,73 +16,72 @@ */ package org.apache.logging.log4j.core.net.ssl; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.Lazy; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import java.util.Optional; +import java.util.function.Supplier; + +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.util.PropertyResolver; + +import static org.apache.logging.log4j.core.impl.Log4jProperties.*; /** * Creates an SSL configuration from Log4j properties. */ -public class SslConfigurationFactory { +public class SslConfigurationFactory implements Supplier { - private static final Logger LOGGER = StatusLogger.getLogger(); + private final PropertyResolver propertyResolver; - private static final Lazy SSL_CONFIGURATION = Lazy.lazy(() -> { - final PropertyEnvironment props = PropertiesUtil.getProperties(); - return createSslConfiguration(props); - }); + @Inject + public SslConfigurationFactory(final PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + } - static SslConfiguration createSslConfiguration(final PropertyEnvironment props) { - KeyStoreConfiguration keyStoreConfiguration = null; - TrustStoreConfiguration trustStoreConfiguration = null; - String location = props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_LOCATION); - if (location != null) { - final String password = props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_PASSWORD); - char[] passwordChars = null; - if (password != null) { - passwordChars = password.toCharArray(); - } - try { - trustStoreConfiguration = TrustStoreConfiguration.createKeyStoreConfiguration(location, passwordChars, - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_ENV_VAR), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_FILE), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_KEY_STORE_TYPE), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_TRUST_STORE_KEY_MANAGER_FACTORY_ALGORITHM)); - } catch (final Exception ex) { - LOGGER.warn("Unable to create trust store configuration due to: {} {}", ex.getClass().getName(), - ex.getMessage()); - } - } - location = props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_LOCATION); - if (location != null) { - final String password = props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_PASSWORD); - char[] passwordChars = null; - if (password != null) { - passwordChars = password.toCharArray(); - } - try { - keyStoreConfiguration = KeyStoreConfiguration.createKeyStoreConfiguration(location, passwordChars, - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_PASSWORD_ENV_VAR), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_PASSWORD_FILE), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_TYPE), - props.getStringProperty(Log4jProperties.TRANSPORT_SECURITY_KEY_STORE_KEY_MANAGER_FACTORY_ALGORITHM)); - } catch (final Exception ex) { - LOGGER.warn("Unable to create key store configuration due to: {} {}", ex.getClass().getName(), - ex.getMessage()); - } - } + @Override + public SslConfiguration get() { + final String trustStoreAlgorithm = + propertyResolver.getString(TRANSPORT_SECURITY_TRUST_STORE_KEY_MANAGER_FACTORY_ALGORITHM) + .orElse(null); + final TrustStoreConfiguration trustStoreConfiguration = initKeyStoreConfigBuilder( + TrustStoreConfiguration::builder, + TRANSPORT_SECURITY_TRUST_STORE_LOCATION, + TRANSPORT_SECURITY_TRUST_STORE_PASSWORD, + TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_ENV_VAR, + TRANSPORT_SECURITY_TRUST_STORE_PASSWORD_FILE, + TRANSPORT_SECURITY_TRUST_STORE_KEY_STORE_TYPE) + .map(builder -> builder.setTrustManagerFactoryAlgorithm(trustStoreAlgorithm).get()) + .orElse(null); + final String keyStoreAlgorithm = + propertyResolver.getString(TRANSPORT_SECURITY_KEY_STORE_KEY_MANAGER_FACTORY_ALGORITHM) + .orElse(null); + final KeyStoreConfiguration keyStoreConfiguration = initKeyStoreConfigBuilder( + KeyStoreConfiguration::builder, + TRANSPORT_SECURITY_KEY_STORE_LOCATION, + TRANSPORT_SECURITY_KEY_STORE_PASSWORD, + TRANSPORT_SECURITY_KEY_STORE_PASSWORD_ENV_VAR, + TRANSPORT_SECURITY_KEY_STORE_PASSWORD_FILE, + TRANSPORT_SECURITY_KEY_STORE_TYPE) + .map(builder -> builder.setKeyManagerFactoryAlgorithm(keyStoreAlgorithm).get()) + .orElse(null); if (trustStoreConfiguration != null || keyStoreConfiguration != null) { - final boolean isVerifyHostName = props.getBooleanProperty(Log4jProperties.TRANSPORT_SECURITY_VERIFY_HOST_NAME, false); - return SslConfiguration.createSSLConfiguration(null, keyStoreConfiguration, - trustStoreConfiguration, isVerifyHostName); + final boolean isVerifyHostName = propertyResolver.getBoolean(TRANSPORT_SECURITY_VERIFY_HOST_NAME); + return SslConfiguration.createSSLConfiguration(null, keyStoreConfiguration, trustStoreConfiguration, isVerifyHostName); } return null; } - public static SslConfiguration getSslConfiguration() { - return SSL_CONFIGURATION.value(); + private , C extends AbstractKeyStoreConfiguration> + Optional initKeyStoreConfigBuilder(final Supplier builderFactory, + final String locationKey, + final String passwordKey, + final String passwordEnvVarKey, + final String passwordFileKey, + final String keyStoreTypeKey) { + return propertyResolver.getString(locationKey) + .map(location -> builderFactory.get() + .setLocation(location) + .setPassword(propertyResolver.getString(passwordKey).map(String::toCharArray).orElse(null)) + .setPasswordEnvironmentVariable(propertyResolver.getString(passwordEnvVarKey).orElse(null)) + .setPasswordFile(propertyResolver.getString(passwordFileKey).orElse(null)) + .setKeyStoreType(propertyResolver.getString(keyStoreTypeKey).orElse(null))); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java index d1462f146a9..209ad2019c6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java @@ -18,8 +18,11 @@ import java.util.Arrays; import java.util.Objects; +import java.util.function.Supplier; +import org.apache.logging.log4j.plugins.PluginAttribute; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Cast; /** * @@ -99,4 +102,64 @@ public boolean equals(final Object obj) { } return true; } + + public static abstract class Builder, C extends StoreConfiguration, S> + implements Supplier { + private String location; + private char[] password; + private String passwordEnvironmentVariable; + private String passwordFile; + + protected B asBuilder() { + return Cast.cast(this); + } + + public String getLocation() { + return location; + } + + public B setLocation(@PluginAttribute final String location) { + this.location = location; + return asBuilder(); + } + + public char[] getPassword() { + return password; + } + + public B setPassword(@PluginAttribute(sensitive = true) final char[] password) { + this.password = password; + return asBuilder(); + } + + public String getPasswordEnvironmentVariable() { + return passwordEnvironmentVariable; + } + + public B setPasswordEnvironmentVariable(@PluginAttribute final String passwordEnvironmentVariable) { + this.passwordEnvironmentVariable = passwordEnvironmentVariable; + return asBuilder(); + } + + public String getPasswordFile() { + return passwordFile; + } + + public B setPasswordFile(@PluginAttribute final String passwordFile) { + this.passwordFile = passwordFile; + return asBuilder(); + } + + public abstract C build() throws StoreConfigurationException; + + @Override + public C get() { + try { + return build(); + } catch (final StoreConfigurationException e) { + LOGGER.warn("Unable to configure keystore", e); + return null; + } + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java index 81db690aecf..ee0ce3c69ab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java @@ -16,16 +16,15 @@ */ package org.apache.logging.log4j.core.net.ssl; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.TrustManagerFactory; + import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginAttribute; import org.apache.logging.log4j.plugins.PluginFactory; -import javax.net.ssl.TrustManagerFactory; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - /** * Configuration of the TrustStore */ @@ -35,73 +34,16 @@ public class TrustStoreConfiguration extends AbstractKeyStoreConfiguration { private final String trustManagerFactoryAlgorithm; - public TrustStoreConfiguration(final String location, - final PasswordProvider passwordProvider, - final String keyStoreType, - final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { + private TrustStoreConfiguration(final String location, + final PasswordProvider passwordProvider, + final String keyStoreType, + final String trustManagerFactoryAlgorithm) + throws StoreConfigurationException { super(location, passwordProvider, keyStoreType); this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm == null ? TrustManagerFactory .getDefaultAlgorithm() : trustManagerFactoryAlgorithm; } - /** - * @deprecated Use {@link #TrustStoreConfiguration(String, PasswordProvider, String, String)} instead - */ - @Deprecated - public TrustStoreConfiguration(final String location, final char[] password, final String keyStoreType, - final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { - this(location, new MemoryPasswordProvider(password), keyStoreType, trustManagerFactoryAlgorithm); - if (password != null) { - Arrays.fill(password, '\0'); - } - } - - /** - * Creates a KeyStoreConfiguration. - * - * @param location - * The location of the KeyStore, a file path, URL or resource. - * @param password - * The password to access the KeyStore. - * @param keyStoreType - * The KeyStore type, null defaults to {@code "JKS"}. - * @param trustManagerFactoryAlgorithm - * The standard name of the requested trust management algorithm. See the Java Secure Socket Extension Reference Guide for information these names. - * @return a new TrustStoreConfiguration - * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore. - */ - @PluginFactory - public static TrustStoreConfiguration createKeyStoreConfiguration( - // @formatter:off - @PluginAttribute final String location, - @PluginAttribute(sensitive = true) final char[] password, - @PluginAttribute final String passwordEnvironmentVariable, - @PluginAttribute final String passwordFile, - @PluginAttribute("type") final String keyStoreType, - @PluginAttribute final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { - // @formatter:on - - if (password != null && passwordEnvironmentVariable != null && passwordFile != null) { - throw new IllegalStateException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'."); - } - try { - // @formatter:off - final PasswordProvider provider = passwordFile != null - ? new FilePasswordProvider(passwordFile) - : passwordEnvironmentVariable != null - ? new EnvironmentPasswordProvider(passwordEnvironmentVariable) - // the default is memory char[] array, which may be null - : new MemoryPasswordProvider(password); - // @formatter:on - if (password != null) { - Arrays.fill(password, '\0'); - } - return new TrustStoreConfiguration(location, provider, keyStoreType, trustManagerFactoryAlgorithm); - } catch (final Exception ex) { - throw new StoreConfigurationException("Could not configure TrustStore", ex); - } - } - public TrustManagerFactory initTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException { final TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(this.trustManagerFactoryAlgorithm); tmFactory.init(this.getKeyStore()); @@ -142,4 +84,28 @@ public boolean equals(final Object obj) { public String getTrustManagerFactoryAlgorithm() { return trustManagerFactoryAlgorithm; } + + @PluginFactory + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractKeyStoreConfiguration.Builder { + private String trustManagerFactoryAlgorithm; + + public String getTrustManagerFactoryAlgorithm() { + return trustManagerFactoryAlgorithm; + } + + public Builder setTrustManagerFactoryAlgorithm(@PluginAttribute final String trustManagerFactoryAlgorithm) { + this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm; + return this; + } + + @Override + public TrustStoreConfiguration build() throws StoreConfigurationException { + return new TrustStoreConfiguration(getLocation(), buildPasswordProvider(), getKeyStoreType(), + getTrustManagerFactoryAlgorithm()); + } + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java index ef0ebaa17d4..26703bcad53 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java @@ -71,10 +71,6 @@ public int getOrder() { registry.loadServicesFromBundle(PluginService.class, bundleId, classLoader); registry.loadServicesFromBundle(ContextDataProvider.class, bundleId, classLoader); registry.loadServicesFromBundle(InjectorCallback.class, bundleId, classLoader); - // allow the user to override the default ContextSelector (e.g., by using BasicContextSelector for a global cfg) - if (PropertiesUtil.getProperties().getStringProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME) == null) { - System.setProperty(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME, BundleContextSelector.class.getName()); - } contextRef.compareAndSet(null, context); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java deleted file mode 100644 index 718c0bf6fc0..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.osgi; - -import java.lang.ref.WeakReference; -import java.net.URI; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.impl.ContextAnchor; -import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; -import org.apache.logging.log4j.plugins.Inject; -import org.apache.logging.log4j.plugins.Singleton; -import org.apache.logging.log4j.plugins.di.Injector; -import org.apache.logging.log4j.util.StackLocatorUtil; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleReference; -import org.osgi.framework.FrameworkUtil; - -/** - * ContextSelector for OSGi bundles. This ContextSelector works rather similarly to the - * {@link ClassLoaderContextSelector}, but instead of each ClassLoader having its own LoggerContext (like in a - * servlet container), each OSGi bundle has its own LoggerContext. - * - * @since 2.1 - */ -@Singleton -public class BundleContextSelector extends ClassLoaderContextSelector { - @Inject - public BundleContextSelector(final Injector injector) { - super(injector); - } - - @Override - public void shutdown(final String fqcn, final ClassLoader loader, final boolean currentContext, - final boolean allContexts) { - LoggerContext ctx = null; - Bundle bundle = null; - if (currentContext) { - ctx = ContextAnchor.THREAD_CONTEXT.get(); - ContextAnchor.THREAD_CONTEXT.remove(); - } - if (ctx == null && loader instanceof BundleReference) { - bundle = ((BundleReference) loader).getBundle(); - ctx = getLoggerContext(bundle); - removeLoggerContext(ctx); - } - if (ctx == null) { - final Class callerClass = StackLocatorUtil.getCallerClass(fqcn); - if (callerClass != null) { - bundle = FrameworkUtil.getBundle(callerClass); - ctx = getLoggerContext(FrameworkUtil.getBundle(callerClass)); - removeLoggerContext(ctx); - } - } - if (ctx == null) { - ctx = ContextAnchor.THREAD_CONTEXT.get(); - ContextAnchor.THREAD_CONTEXT.remove(); - } - if (ctx != null) { - ctx.stop(DEFAULT_STOP_TIMEOUT, TimeUnit.MILLISECONDS); - } - if (bundle != null && allContexts) { - final Bundle[] bundles = bundle.getBundleContext().getBundles(); - for (final Bundle bdl : bundles) { - ctx = getLoggerContext(bdl); - if (ctx != null) { - ctx.stop(DEFAULT_STOP_TIMEOUT, TimeUnit.MILLISECONDS); - } - } - } - } - - private LoggerContext getLoggerContext(final Bundle bundle) { - final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName(); - final AtomicReference> ref = contextMap.get(name); - if (ref != null && ref.get() != null) { - return ref.get().get(); - } - return null; - } - - private void removeLoggerContext(final LoggerContext context) { - contextMap.remove(context.getName()); - } - - @Override - public boolean hasContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { - if (currentContext && ContextAnchor.THREAD_CONTEXT.get() != null) { - return ContextAnchor.THREAD_CONTEXT.get().isStarted(); - } - if (loader instanceof BundleReference) { - return hasContext(((BundleReference) loader).getBundle()); - } - final Class callerClass = StackLocatorUtil.getCallerClass(fqcn); - if (callerClass != null) { - return hasContext(FrameworkUtil.getBundle(callerClass)); - } - return ContextAnchor.THREAD_CONTEXT.get() != null && ContextAnchor.THREAD_CONTEXT.get().isStarted(); - } - - @Override - public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, - final URI configLocation) { - if (currentContext) { - final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get(); - if (ctx != null) { - return ctx; - } - return getDefault(); - } - // it's quite possible that the provided ClassLoader may implement BundleReference which gives us a nice shortcut - if (loader instanceof BundleReference) { - return locateContext(((BundleReference) loader).getBundle(), configLocation); - } - final Class callerClass = StackLocatorUtil.getCallerClass(fqcn); - if (callerClass != null) { - return locateContext(FrameworkUtil.getBundle(callerClass), configLocation); - } - final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); - return lc == null ? getDefault() : lc; - } - - private boolean hasContext(final Bundle bundle) { - final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName(); - final AtomicReference> ref = contextMap.get(name); - return ref != null && ref.get() != null && ref.get().get() != null && ref.get().get().isStarted(); - } - - private LoggerContext locateContext(final Bundle bundle, final URI configLocation) { - final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName(); - final AtomicReference> ref = contextMap.get(name); - if (ref == null) { - final LoggerContext context = new LoggerContext(name, bundle, configLocation); - contextMap.putIfAbsent(name, - new AtomicReference<>(new WeakReference<>(context))); - return contextMap.get(name).get().get(); - } - final WeakReference r = ref.get(); - final LoggerContext ctx = r.get(); - if (ctx == null) { - final LoggerContext context = new LoggerContext(name, bundle, configLocation); - ref.compareAndSet(r, new WeakReference<>(context)); - return ref.get().get(); - } - final URI oldConfigLocation = ctx.getConfigLocation(); - if (oldConfigLocation == null && configLocation != null) { - LOGGER.debug("Setting bundle ({}) configuration to {}", name, configLocation); - ctx.setConfigLocation(configLocation); - } else if (oldConfigLocation != null && configLocation != null && !configLocation.equals(oldConfigLocation)) { - LOGGER.warn("locateContext called with URI [{}], but existing LoggerContext has URI [{}]", - configLocation, oldConfigLocation); - } - return ctx; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java index 8c36c1100e7..de246acd47c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java @@ -16,20 +16,21 @@ */ package org.apache.logging.log4j.core.parser; +import java.io.IOException; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; - -import java.io.IOException; public class AbstractJacksonLogEventParser implements TextLogEventParser { private final ObjectReader objectReader; protected AbstractJacksonLogEventParser(final ObjectMapper objectMapper) { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - this.objectReader = objectMapper.readerFor(Log4jLogEvent.class); + this.objectReader = objectMapper.readerFor(ImmutableLogEvent.class); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java index 7acc38b5543..3180d5707ab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java @@ -22,6 +22,7 @@ import java.text.ParsePosition; import java.util.Date; import java.util.TimeZone; +import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.core.util.Constants; @@ -92,6 +93,8 @@ final class CachedDateFormat extends DateFormat { private static final long SLOTS = 1000L; + private static final long MILLIS_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); + /** * Wrapped formatter. */ @@ -170,10 +173,10 @@ public CachedDateFormat(final DateFormat dateFormat, final int expiration) { * field (likely RelativeTimeDateFormat) */ public static int findMillisecondStart(final long time, final String formatted, final DateFormat formatter) { - long slotBegin = (time / Constants.MILLIS_IN_SECONDS) * Constants.MILLIS_IN_SECONDS; + long slotBegin = (time / MILLIS_IN_SECONDS) * MILLIS_IN_SECONDS; if (slotBegin > time) { - slotBegin -= Constants.MILLIS_IN_SECONDS; + slotBegin -= MILLIS_IN_SECONDS; } final int millis = (int) (time - slotBegin); @@ -290,10 +293,10 @@ public StringBuffer format(final long now, final StringBuffer buf) { cache.append(formatter.format(tmpDate)); buf.append(cache); previousTime = now; - slotBegin = (previousTime / Constants.MILLIS_IN_SECONDS) * Constants.MILLIS_IN_SECONDS; + slotBegin = (previousTime / MILLIS_IN_SECONDS) * MILLIS_IN_SECONDS; if (slotBegin > previousTime) { - slotBegin -= Constants.MILLIS_IN_SECONDS; + slotBegin -= MILLIS_IN_SECONDS; } // diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index d1864a55f44..1e17e85bb42 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -17,8 +17,8 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java index 1ee7c43d477..f9005504a56 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java @@ -113,7 +113,8 @@ public PatternParser(final String converterKey) { * @param expected * The expected base Class of each Converter. */ - public PatternParser(final Configuration config, final String converterKey, final Class expected) { + public PatternParser(final Configuration config, final String converterKey, + final Class expected) { this(config, converterKey, expected, null); } @@ -129,22 +130,24 @@ public PatternParser(final Configuration config, final String converterKey, fina * @param filterClass * Filter the returned plugins after calling the plugin manager. */ - public PatternParser(final Configuration config, final String converterKey, final Class expectedClass, - final Class filterClass) { + public PatternParser(final Configuration config, final String converterKey, + final Class expectedClass, + final Class filterClass) { this.config = config; final PluginNamespace plugins; final Key pluginCategoryKey = PLUGIN_CATEGORY_KEY.withNamespace(converterKey); if (config == null) { plugins = DI.createInjector().getInstance(pluginCategoryKey); } else { - plugins = config.getComponent(pluginCategoryKey); + plugins = config.getInstance(pluginCategoryKey); } final Map> converters = new LinkedHashMap<>(); + final Class subclass = expectedClass != null ? expectedClass : PatternConverter.class; for (final PluginType type : plugins) { try { - final Class clazz = type.getPluginClass().asSubclass(PatternConverter.class); + final Class clazz = type.getPluginClass().asSubclass(subclass); if (filterClass != null && !filterClass.isAssignableFrom(clazz)) { continue; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java index 76748612e29..7ca09ed956c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java @@ -17,8 +17,8 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java index 4d3e0299751..03511e056ce 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java @@ -23,12 +23,15 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.ContextAnchor; +import org.apache.logging.log4j.plugins.ContextScoped; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.SimpleScope; import org.apache.logging.log4j.spi.LoggerContextShutdownAware; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Lazy; +import org.apache.logging.log4j.util.PropertyResolver; /** * Returns either this Thread's context or the default LoggerContext. @@ -40,10 +43,12 @@ public class BasicContextSelector implements ContextSelector, LoggerContextShutd protected final Lazy context = Lazy.lazy(this::createContext); protected final Injector injector; + protected final PropertyResolver propertyResolver; @Inject - public BasicContextSelector(final Injector injector) { + public BasicContextSelector(final Injector injector, final PropertyResolver propertyResolver) { this.injector = injector; + this.propertyResolver = propertyResolver; } @Override @@ -94,6 +99,12 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin return ctx; } + @Override + public LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final boolean currentContext, final URI configLocation) { + return getContext(fqcn, loader, currentContext, configLocation); + } + @Override public void removeContext(final LoggerContext context) { if (context == this.context.get()) { @@ -112,6 +123,10 @@ public List getLoggerContexts() { } protected LoggerContext createContext() { - return new LoggerContext("Default", null, (URI) null, injector); + final Injector loggerContextInjector = injector.copy(); + loggerContextInjector.registerScope(ContextScoped.class, new SimpleScope("LoggerContext; name=Default")); + final LoggerContext.Builder builder = LoggerContext.newBuilder().setName("Default"); + loggerContextInjector.injectMembers(builder); + return builder.get(); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java index f5f91b73836..ef452af8909 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java @@ -28,13 +28,17 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.LoggerContextNamingStrategy; import org.apache.logging.log4j.core.impl.ContextAnchor; +import org.apache.logging.log4j.plugins.ContextScoped; import org.apache.logging.log4j.plugins.Inject; import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.SimpleScope; import org.apache.logging.log4j.spi.LoggerContextShutdownAware; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Lazy; +import org.apache.logging.log4j.util.PropertyResolver; import org.apache.logging.log4j.util.StackLocatorUtil; /** @@ -53,14 +57,27 @@ public class ClassLoaderContextSelector implements ContextSelector, LoggerContex protected static final StatusLogger LOGGER = StatusLogger.getLogger(); - protected final Lazy defaultContext = Lazy.lazy(() -> createContext(defaultContextName(), null)); + protected final Lazy defaultContext; protected final Map>> contextMap = new ConcurrentHashMap<>(); protected final Injector injector; + protected final PropertyResolver propertyResolver; + protected final LoggerContextNamingStrategy namingStrategy; @Inject - public ClassLoaderContextSelector(final Injector injector) { + public ClassLoaderContextSelector(final Injector injector, final PropertyResolver propertyResolver, + final LoggerContextNamingStrategy namingStrategy) { this.injector = injector; + this.propertyResolver = propertyResolver; + this.defaultContext = Lazy.lazy(() -> { + final Injector loggerContextInjector = injector.copy(); + final String contextName = defaultContextName(); + loggerContextInjector.registerScope(ContextScoped.class, new SimpleScope("LoggerContext; name=" + contextName)); + final LoggerContext.Builder builder = LoggerContext.newBuilder().setName(contextName); + loggerContextInjector.injectMembers(builder); + return builder.get(); + }); + this.namingStrategy = namingStrategy; } @Override @@ -113,8 +130,8 @@ public boolean hasContext(final String fqcn, final ClassLoader loader, final boo private LoggerContext findContext(final ClassLoader loaderOrNull) { final ClassLoader loader = loaderOrNull != null ? loaderOrNull : ClassLoader.getSystemClassLoader(); - final String name = toContextMapKey(loader); - final AtomicReference> ref = contextMap.get(name); + final String contextKey = toContextMapKey(loader); + final AtomicReference> ref = contextMap.get(contextKey); if (ref != null) { final WeakReference weakRef = ref.get(); return weakRef.get(); @@ -134,6 +151,31 @@ public LoggerContext getContext( return getContext(fqcn, loader, null, currentContext, configLocation); } + @Override + public LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final boolean currentContext, final URI configLocation) { + if (currentContext) { + final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get(); + if (ctx != null) { + return ctx; + } + return getDefault(); + } + if (loader != null) { + return locateContext(loader, null, configLocation, name); + } + final Class clazz = StackLocatorUtil.getCallerClass(fqcn); + if (clazz != null) { + final ClassLoader classLoader = clazz.getClassLoader(); + return locateContext(classLoader, null, configLocation, name); + } + final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); + if (lc != null) { + return lc; + } + return getDefault(); + } + @Override public LoggerContext getContext( final String fqcn, final ClassLoader loader, final Map.Entry entry, @@ -144,19 +186,21 @@ public LoggerContext getContext( return ctx; } return getDefault(); - } else if (loader != null) { - return locateContext(loader, entry, configLocation); - } else { - final Class clazz = StackLocatorUtil.getCallerClass(fqcn); - if (clazz != null) { - return locateContext(clazz.getClassLoader(), entry, configLocation); - } - final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); - if (lc != null) { - return lc; - } - return getDefault(); } + final String name = namingStrategy.getName(configLocation, loader, null, entry); + if (loader != null) { + return locateContext(loader, entry, configLocation, name); + } + final Class clazz = StackLocatorUtil.getCallerClass(fqcn); + if (clazz != null) { + final ClassLoader classLoader = clazz.getClassLoader(); + return locateContext(classLoader, entry, configLocation, name); + } + final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); + if (lc != null) { + return lc; + } + return getDefault(); } @Override @@ -188,24 +232,13 @@ public List getLoggerContexts() { return Collections.unmodifiableList(list); } - private Injector getOrCopyInjector(final Map.Entry entry) { - if (entry != null) { - final Object value = entry.getValue(); - if (value instanceof Injector) { - return (Injector) value; - } - } - final Injector injector = this.injector; - return injector != null ? injector.copy() : null; - } - private LoggerContext locateContext( final ClassLoader loaderOrNull, final Map.Entry entry, - final URI configLocation) { + final URI configLocation, final String name) { // LOG4J2-477: class loader may be null final ClassLoader loader = loaderOrNull != null ? loaderOrNull : ClassLoader.getSystemClassLoader(); - final String name = toContextMapKey(loader); - AtomicReference> ref = contextMap.get(name); + final String key = toContextMapKey(loader); + AtomicReference> ref = contextMap.get(key); if (ref == null) { if (configLocation == null) { ClassLoader parent = loader.getParent(); @@ -239,11 +272,11 @@ private LoggerContext locateContext( } */ } } - final LoggerContext ctx = createContext(name, configLocation, getOrCopyInjector(entry)); + final LoggerContext ctx = createContext(key, name, configLocation); if (entry != null) { ctx.putObject(entry.getKey(), entry.getValue()); } - final LoggerContext newContext = contextMap.computeIfAbsent(name, + final LoggerContext newContext = contextMap.computeIfAbsent(key, k -> new AtomicReference<>(new WeakReference<>(ctx))).get().get(); if (newContext != null && newContext == ctx) { newContext.addShutdownListener(this); @@ -266,7 +299,7 @@ private LoggerContext locateContext( } return ctx; } - ctx = createContext(name, configLocation, getOrCopyInjector(entry)); + ctx = createContext(key, name, configLocation); if (entry != null) { ctx.putObject(entry.getKey(), entry.getValue()); } @@ -276,14 +309,15 @@ private LoggerContext locateContext( return ctx; } - protected LoggerContext createContext(final String name, final URI configLocation) { - final Injector injector = this.injector; - return createContext(name, configLocation, injector != null ? injector.copy() : null); - } - - protected LoggerContext createContext(final String name, final URI configLocation, final Injector injector) { - - return new LoggerContext(name, null, configLocation, injector); + protected LoggerContext createContext(final String key, final String name, final URI configLocation) { + final Injector loggerContextInjector = injector.copy(); + loggerContextInjector.registerScope(ContextScoped.class, new SimpleScope("LoggerContext; name=" + name)); + final LoggerContext.Builder builder = LoggerContext.newBuilder() + .setKey(key) + .setName(name) + .setConfigLocation(configLocation); + loggerContextInjector.injectMembers(builder); + return builder.get(); } protected String toContextMapKey(final ClassLoader loader) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java index e98323a1aa0..bbc8df49518 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java @@ -16,13 +16,15 @@ */ package org.apache.logging.log4j.core.selector; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.plugins.di.Key; - import java.net.URI; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.Key; /** * Interface used to locate a LoggerContext. @@ -71,6 +73,20 @@ default boolean hasContext(final String fqcn, final ClassLoader loader, final bo */ LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext); + /** + * Returns the LoggerContext. + * @param fqcn The fully qualified class name of the caller. + * @param name The name of the Context. + * @param loader ClassLoader to use or null. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @return The LoggerContext. + */ + default LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final boolean currentContext) { + return getContext(fqcn, name, loader, currentContext, null); + } + /** * Returns the LoggerContext. * @param fqcn The fully qualified class name of the caller. @@ -80,7 +96,8 @@ default boolean hasContext(final String fqcn, final ClassLoader loader, final bo * for the caller if a more appropriate Context can be determined. * @return The LoggerContext. */ - default LoggerContext getContext(final String fqcn, final ClassLoader loader, final Map.Entry entry, final boolean currentContext) { + default LoggerContext getContext(final String fqcn, final ClassLoader loader, final Map.Entry entry, + final boolean currentContext) { final LoggerContext lc = getContext(fqcn, loader, currentContext); if (entry != null) { lc.putObject(entry.getKey(), entry.getValue()); @@ -100,17 +117,31 @@ default LoggerContext getContext(final String fqcn, final ClassLoader loader, fi */ LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext, URI configLocation); + /** + * Returns the LoggerContext. + * @param fqcn The fully qualified class name of the caller. + * @param name The name of the Context. + * @param loader ClassLoader to use or null. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @param configLocation The location of the configuration for the LoggerContext. + * @return The LoggerContext. + */ + LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final boolean currentContext, final URI configLocation); + /** * Returns the LoggerContext. * @param fqcn The fully qualified class name of the caller. * @param loader ClassLoader to use or null. + * @param entry An entry for the external Context map. * @param currentContext If true returns the current Context, if false returns the Context appropriate * for the caller if a more appropriate Context can be determined. * @param configLocation The location of the configuration for the LoggerContext. * @return The LoggerContext. */ default LoggerContext getContext(final String fqcn, final ClassLoader loader, final Map.Entry entry, - final boolean currentContext, final URI configLocation) { + final boolean currentContext, final URI configLocation) { final LoggerContext lc = getContext(fqcn, loader, currentContext, configLocation); if (entry != null) { lc.putObject(entry.getKey(), entry.getValue()); @@ -118,6 +149,27 @@ default LoggerContext getContext(final String fqcn, final ClassLoader loader, fi return lc; } + /** + * Returns the LoggerContext. + * @param fqcn The fully qualified class name of the caller. + * @param name The name of the Context. + * @param loader ClassLoader to use or null. + * @param entry An entry for the external Context map. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @param configLocation The location of the configuration for the LoggerContext. + * @return The LoggerContext. + */ + default LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final Map.Entry entry, final boolean currentContext, + final URI configLocation) { + final LoggerContext lc = getContext(fqcn, name, loader, currentContext, configLocation); + if (entry != null) { + lc.putObject(entry.getKey(), entry.getValue()); + } + return lc; + } + /** * Returns a List of all the available LoggerContexts. * @return The List of LoggerContexts. @@ -131,7 +183,7 @@ default LoggerContext getContext(final String fqcn, final ClassLoader loader, fi void removeContext(LoggerContext context); /** - * Determines whether or not this ContextSelector depends on the callers classloader. + * Determines whether this ContextSelector depends on the callers classloader. * This method should be overridden by implementations, however a default method is provided which always * returns {@code true} to preserve the old behavior. * diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java index d09537c2b35..c5921564df5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java @@ -21,7 +21,7 @@ import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.core.time.PreciseClock; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; /** * Implementation of the {@code Clock} interface that returns the system time. @@ -29,11 +29,6 @@ */ public final class SystemClock implements Clock, PreciseClock { - /** - * The precise clock is not enabled by default, since access to it is not garbage free. - */ - private static final boolean USE_PRECISE_CLOCK = PropertiesUtil.getProperties() - .getBooleanProperty("log4j2.usePreciseClock", false); /** * Returns the system time. * @return the result of calling {@code System.currentTimeMillis()} @@ -48,7 +43,7 @@ public long currentTimeMillis() { */ @Override public void init(final MutableInstant mutableInstant) { - if (USE_PRECISE_CLOCK) { + if (GarbageFreeConfiguration.getDefaultConfiguration().isPreciseClockEnabled()) { final Instant instant = java.time.Clock.systemUTC().instant(); mutableInstant.initFromEpochSecond(instant.getEpochSecond(), instant.getNano()); } else { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java index 287fbf9cc23..702dba19c71 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java @@ -17,49 +17,45 @@ package org.apache.logging.log4j.core.util; import java.net.URLConnection; +import java.nio.charset.StandardCharsets; import java.util.Base64; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.plugins.di.Injector; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.PropertyResolver; /** * Provides the Basic Authorization header to a request. */ +@ContextScoped public class BasicAuthorizationProvider implements AuthorizationProvider { - private static final String[] PREFIXES = {"log4j2.config.", "log4j2.Configuration.", "logging.auth."}; - private static final String AUTH_USER_NAME = "username"; - private static final String AUTH_PASSWORD = "password"; - private static final String AUTH_PASSWORD_DECRYPTOR = "passwordDecryptor"; - public static final String CONFIG_USER_NAME = "log4j2.configurationUserName"; - public static final String CONFIG_PASSWORD = "log4j2.configurationPassword"; - public static final String PASSWORD_DECRYPTOR = "log4j2.passwordDecryptor"; private static final Logger LOGGER = StatusLogger.getLogger(); private static final Base64.Encoder encoder = Base64.getEncoder(); private String authString = null; - public BasicAuthorizationProvider(final PropertyEnvironment props) { - final String userName = props.getStringProperty(PREFIXES,AUTH_USER_NAME, - () -> props.getStringProperty(CONFIG_USER_NAME)); - String password = props.getStringProperty(PREFIXES, AUTH_PASSWORD, - () -> props.getStringProperty(CONFIG_PASSWORD)); - final String decryptor = props.getStringProperty(PREFIXES, AUTH_PASSWORD_DECRYPTOR, - () -> props.getStringProperty(PASSWORD_DECRYPTOR)); - if (decryptor != null) { - try { - final Object obj = LoaderUtil.newInstanceOf(decryptor); - if (obj instanceof PasswordDecryptor) { - password = ((PasswordDecryptor) obj).decryptPassword(password); - } - } catch (final Exception ex) { - LOGGER.warn("Unable to decrypt password.", ex); - } - } - if (userName != null && password != null) { - authString = "Basic " + encoder.encodeToString((userName + ":" + password).getBytes()); + @Inject + public BasicAuthorizationProvider(final PropertyResolver resolver, final Injector injector) { + final String user = resolver.getString(Log4jProperties.TRANSPORT_SECURITY_BASIC_USERNAME).orElse(null); + final String pass = resolver.getString(Log4jProperties.TRANSPORT_SECURITY_BASIC_PASSWORD) + .map(password -> injector.tryGetInstance(PasswordDecryptor.class) + .map(passwordDecryptor -> { + try { + return passwordDecryptor.decryptPassword(password); + } catch (final Exception e) { + LOGGER.warn("Unable to decrypt password", e); + return null; + } + }) + .orElse(password)) + .orElse(null); + if (user != null && pass != null) { + authString = "Basic " + encoder.encodeToString((user + ':' + pass).getBytes(StandardCharsets.UTF_8)); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Closer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Closer.java index 9c0c46db412..e18d149a945 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Closer.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Closer.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.core.util; +import java.util.stream.Stream; + import org.apache.logging.log4j.status.StatusLogger; /** @@ -60,4 +61,8 @@ public static boolean closeSilently(final AutoCloseable closeable) { } } + public static boolean closeAllSilently(final AutoCloseable... instances) { + return Stream.of(instances).filter(Closer::closeSilently).count() == instances.length; + } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java index 62fc657e368..d06f14754d2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java @@ -16,17 +16,14 @@ */ package org.apache.logging.log4j.core.util; -import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.plugins.Named; -import org.apache.logging.log4j.plugins.di.Key; -import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.util.LoaderUtil; import org.apache.logging.log4j.util.PropertiesUtil; /** * Log4j Constants. */ +@Deprecated(forRemoval = true) // TODO(ms): finish migrating config values from here public final class Constants { public static final String JNDI_PREFIX = "log4j2.enableJndi"; @@ -38,6 +35,7 @@ public final class Constants { * @return true if the feature is available. */ private static boolean isJndiEnabled(final String subKey) { + // FIXME(ms): check updated property names return PropertiesUtil.getProperties().getBooleanProperty(JNDI_PREFIX + subKey, false) && isClassAvailable(JNDI_MANAGER_CLASS); } @@ -50,11 +48,6 @@ private static boolean isJndiEnabled(final String subKey) { public static boolean JNDI_JDBC_ENABLED = isJndiEnabled("Jdbc"); - /** - * Name of the system property to use to identify the LogEvent factory. - */ - public static final String LOG4J_LOG_EVENT_FACTORY = Log4jProperties.LOG_EVENT_FACTORY_CLASS_NAME; - /** * Name of the system property to use to identify the ContextSelector Class. */ @@ -65,84 +58,11 @@ private static boolean isJndiEnabled(final String subKey) { */ public static final String LOG4J_DEFAULT_STATUS_LEVEL = Log4jProperties.STATUS_DEFAULT_LEVEL; - public static final Key DEFAULT_STATUS_LEVEL_KEY = new @Named("StatusLogger") Key<>() {}; - /** * JNDI context name string literal. */ public static final String JNDI_CONTEXT_NAME = "java:comp/env/log4j/context-name"; - /** - * Number of milliseconds in a second. - */ - public static final int MILLIS_IN_SECONDS = 1000; - - /** - * Supports user request LOG4J2-898 to have the option to format a message in the background thread. - */ - public static final boolean FORMAT_MESSAGES_IN_BACKGROUND = PropertiesUtil.getProperties().getBooleanProperty( - Log4jProperties.ASYNC_LOGGER_FORMAT_MESSAGES_IN_BACKGROUND, false); - - /** - * Kill switch for garbage-free Layout behaviour that encodes LogEvents directly into - * {@link org.apache.logging.log4j.core.layout.ByteBufferDestination}s without creating intermediate temporary - * Objects. - *

    - * {@code True} by default iff all loggers are asynchronous because system property - * {@code Log4jContextSelector} is set to {@code org.apache.logging.log4j.core.async.AsyncLoggerContextSelector}. - * Disable by setting system property "log4j2.enable.direct.encoders" to "false". - * - * @since 2.6 - */ - public static final boolean ENABLE_DIRECT_ENCODERS = PropertiesUtil.getProperties().getBooleanProperty( - Log4jProperties.GC_ENABLE_DIRECT_ENCODERS, true); // enable GC-free text encoding by default - // the alternative is to enable GC-free encoding only by default only when using all-async loggers: - //AsyncLoggerContextSelector.class.getName().equals(PropertiesUtil.getProperties().getStringProperty(LOG4J_CONTEXT_SELECTOR))); - - /** - * Initial StringBuilder size used in RingBuffer LogEvents to store the contents of reusable Messages. - *

    - * The default value is {@value}, users can override with system property "log4j.initialReusableMsgSize". - *

    - * @since 2.6 - */ - public static final int INITIAL_REUSABLE_MESSAGE_SIZE = size(Log4jProperties.GC_INITIAL_REUSABLE_MESSAGE_SIZE, 128); - - /** - * Maximum size of the StringBuilders used in RingBuffer LogEvents to store the contents of reusable Messages. - * After a large message has been delivered to the appenders, the StringBuilder is trimmed to this size. - *

    - * The default value is {@value}, which allows the StringBuilder to resize three times from its initial size. - * Users can override with system property "log4j.maxReusableMsgSize". - *

    - * @since 2.6 - */ - public static final int MAX_REUSABLE_MESSAGE_SIZE = size(LoggingSystemProperties.GC_REUSABLE_MESSAGE_MAX_SIZE, (128 * 2 + 2) * 2 + 2); - - /** - * Size of CharBuffers used by text encoders. - *

    - * The default value is {@value}, users can override with system property "log4j.encoder.charBufferSize". - *

    - * @since 2.6 - */ - public static final int ENCODER_CHAR_BUFFER_SIZE = size(Log4jProperties.GC_ENCODER_CHAR_BUFFER_SIZE, 2048); - - /** - * Default size of ByteBuffers used to encode LogEvents without allocating temporary objects. - *

    - * The default value is {@value}, users can override with system property "log4j.encoder.byteBufferSize". - *

    - * @see org.apache.logging.log4j.core.layout.ByteBufferDestination - * @since 2.6 - */ - public static final int ENCODER_BYTE_BUFFER_SIZE = size(Log4jProperties.GC_ENCODER_BYTE_BUFFER_SIZE, 8 * 1024); - - - private static int size(final String property, final int defaultValue) { - return PropertiesUtil.getProperties().getIntegerProperty(property, defaultValue); - } - /** * Determines if a named Class can be loaded or not. * diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/GarbageFreeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/GarbageFreeConfiguration.java new file mode 100644 index 00000000000..3ea4e5f779b --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/GarbageFreeConfiguration.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.util; + +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.plugins.ContextScoped; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.spi.LoggingSystem; +import org.apache.logging.log4j.spi.LoggingSystemProperties; +import org.apache.logging.log4j.util.Lazy; +import org.apache.logging.log4j.util.PropertyResolver; + +@ContextScoped +public class GarbageFreeConfiguration { + private static final Lazy DEFAULT_INSTANCE = + Lazy.relaxed(() -> new GarbageFreeConfiguration(LoggingSystem.getPropertyResolver())); + + public static GarbageFreeConfiguration getDefaultConfiguration() { + return DEFAULT_INSTANCE.value(); + } + + private final PropertyResolver propertyResolver; + + @Inject + public GarbageFreeConfiguration(final PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + } + + /** + * Kill switch for garbage-free Layout behaviour that encodes LogEvents directly into + * {@link org.apache.logging.log4j.core.layout.ByteBufferDestination}s without creating intermediate temporary + * Objects. + *

    + * {@code True} by default iff all loggers are asynchronous because system property + * {@value Log4jProperties#CONTEXT_SELECTOR_CLASS_NAME} is set to {@code org.apache.logging.log4j.core.async.AsyncLoggerContextSelector}. + * Disable by setting system property {@value Log4jProperties#GC_ENABLE_DIRECT_ENCODERS} to "false". + * + * @since 3.0.0 + */ + public boolean isDirectEncodersEnabled() { + return propertyResolver.getBoolean(Log4jProperties.GC_ENABLE_DIRECT_ENCODERS, true); + // enable GC-free text encoding by default + // the alternative is to enable GC-free encoding only by default only when using all-async loggers: + //AsyncLoggerContextSelector.class.getName().equals(LoggingSystem.getPropertyResolver().getString(Log4jProperties.CONTEXT_SELECTOR_CLASS_NAME))); + } + + /** + * Initial StringBuilder size used in RingBuffer LogEvents to store the contents of reusable Messages. + *

    + * The default value is 128, users can override with system property {@value Log4jProperties#GC_INITIAL_REUSABLE_MESSAGE_SIZE}. + *

    + * @since 2.6 + */ + public int getInitialReusableMessageSize() { + return propertyResolver.getInt(Log4jProperties.GC_INITIAL_REUSABLE_MESSAGE_SIZE).orElse(128); + } + + /** + * Maximum size of the StringBuilders used in RingBuffer LogEvents to store the contents of reusable Messages. + * After a large message has been delivered to the appenders, the StringBuilder is trimmed to this size. + *

    + * The default value is 518, which allows the StringBuilder to resize three times from its initial size. + * Users can override with system property {@value LoggingSystemProperties#GC_REUSABLE_MESSAGE_MAX_SIZE}. + *

    + * @since 2.6 + */ + public int getMaxReusableMessageSize() { + return propertyResolver.getInt(LoggingSystemProperties.GC_REUSABLE_MESSAGE_MAX_SIZE).orElse((128 * 2 + 2) * 2 + 2); + } + + /** + * Size of CharBuffers used by text encoders. + *

    + * The default value is 2048, users can override with system property {@value Log4jProperties#GC_ENCODER_CHAR_BUFFER_SIZE}. + *

    + * @since 2.6 + */ + public int getEncoderCharBufferSize() { + return propertyResolver.getInt(Log4jProperties.GC_ENCODER_CHAR_BUFFER_SIZE).orElse(2048); + } + + /** + * Default size of ByteBuffers used to encode LogEvents without allocating temporary objects. + *

    + * The default value is 8192, users can override with system property {@value Log4jProperties#GC_ENCODER_BYTE_BUFFER_SIZE}. + *

    + * @see org.apache.logging.log4j.core.layout.ByteBufferDestination + * @since 2.6 + */ + public int getEncoderByteBufferSize() { + return propertyResolver.getInt(Log4jProperties.GC_ENCODER_BYTE_BUFFER_SIZE).orElse(8 * 1024); + } + + public int getLayoutStringBuilderMaxSize() { + return propertyResolver.getInt(Log4jProperties.GC_LAYOUT_STRING_BUILDER_MAX_SIZE).orElse(2048); + } + + /** + * The precise clock is not enabled by default, since access to it is not garbage free. + */ + public boolean isPreciseClockEnabled() { + return propertyResolver.getBoolean(Log4jProperties.GC_USE_PRECISE_CLOCK); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java index aefbeb94039..c99a6867f7e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java @@ -21,10 +21,10 @@ import java.net.URL; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.LoaderUtil; -import org.apache.logging.log4j.util.PropertiesUtil; /** * Load resources (or images) from various sources. @@ -35,9 +35,6 @@ public final class Loader { private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous."; - final static Boolean ignoreTccl = - Boolean.valueOf(PropertiesUtil.getProperties().getStringProperty(LoggingSystemProperties.LOADER_IGNORE_THREAD_CONTEXT_LOADER, null)); - private Loader() { } @@ -306,7 +303,9 @@ public static boolean isJansiAvailable() { * @throws ClassNotFoundException if the specified class name could not be found */ public static Class loadClass(final String className) throws ClassNotFoundException { - if (ignoreTccl) { + final boolean ignoreTCCL = LoggingSystem.getPropertyResolver() + .getBoolean(LoggingSystemProperties.LOADER_IGNORE_THREAD_CONTEXT_LOADER, false, true); + if (ignoreTCCL) { return Class.forName(className); } try { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NullOutputStream.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NullOutputStream.java deleted file mode 100644 index b445cc0aabc..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NullOutputStream.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ - -package org.apache.logging.log4j.core.util; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Writes all data to the famous /dev/null. - *

    - * This output stream has no destination (file/socket etc.) and all bytes written to it are ignored and lost. - *

    - * Originally from Apache Commons IO. - * - * @since 2.3 - */ -public class NullOutputStream extends OutputStream { - - private static final NullOutputStream INSTANCE = new NullOutputStream(); - - /** - * Gets the singleton instance. - * - * @return the singleton instance. - */ - public static NullOutputStream getInstance() { - return INSTANCE; - } - - private NullOutputStream() { - // do nothing - } - - /** - * Does nothing - output to /dev/null. - * - * @param b - * The bytes to write - * @param off - * The start offset - * @param len - * The number of bytes to write - */ - @Override - public void write(final byte[] b, final int off, final int len) { - // to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * - * @param b - * The byte to write - */ - @Override - public void write(final int b) { - // to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * - * @param b - * The bytes to write - * @throws IOException - * never - */ - @Override - public void write(final byte[] b) throws IOException { - // to /dev/null - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java index ad1d1f6580d..0befdb889fc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java @@ -25,8 +25,8 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.SystemPropertiesPropertySource; /** * A convenience class to convert property values to specific types. @@ -382,7 +382,7 @@ private static String substVars(final String val, final Properties props, List KEY = Key.forClass(ShutdownCallbackRegistry.class); - /** - * System property to set to override the global ability to register shutdown hooks. - */ - String SHUTDOWN_HOOK_ENABLED = Log4jProperties.SHUTDOWN_HOOK_ENABLED; - /** * Shared Marker to indicate log messages corresponding to shutdown hooks. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java index 255c70aa090..9c309a29697 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java @@ -23,7 +23,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.logging.log4j.core.impl.Log4jProperties; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.spi.LoggingSystem; +import org.apache.logging.log4j.util.SystemPropertiesPropertySource; /** * Generates a unique ID. The generated UUID will be unique for approximately 8,925 years so long as @@ -38,7 +39,9 @@ public final class UuidUtil { private static final byte VARIANT = (byte) 0x80; private static final int SEQUENCE_MASK = 0x3FFF; private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L; - private static final long INITIAL_UUID_SEQNO = PropertiesUtil.getProperties().getLongProperty(Log4jProperties.UUID_SEQUENCE, 0); + private static final long INITIAL_UUID_SEQNO = LoggingSystem.getPropertyResolver() + .getLong(Log4jProperties.UUID_SEQUENCE) + .orElse(0); private static final long LOW_MASK = 0xffffffffL; private static final long MID_MASK = 0xffff00000000L; @@ -78,7 +81,7 @@ static long initialize(byte[] mac) { System.arraycopy(mac, index, node, 2, length); final ByteBuffer buf = ByteBuffer.wrap(node); long rand = INITIAL_UUID_SEQNO; - String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES); + String assigned = SystemPropertiesPropertySource.getSystemProperty(ASSIGNED_SEQUENCES, null); final long[] sequences; if (assigned == null) { sequences = new long[0]; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java index 457da9181de..7fa7bd71f31 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java @@ -34,8 +34,8 @@ import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.config.ConfigurationFileWatcher; import org.apache.logging.log4j.core.config.ConfigurationScheduler; +import org.apache.logging.log4j.plugins.ConfigurationScoped; import org.apache.logging.log4j.plugins.Inject; -import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.ServiceRegistry; @@ -45,7 +45,7 @@ * @see FileWatcher * @see ConfigurationScheduler */ -@Singleton +@ConfigurationScoped public class WatchManager extends AbstractLifeCycle { private static final class ConfigurationMonitor { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatcherFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatcherFactory.java index 3aff76f6b15..bb7586cf9fa 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatcherFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatcherFactory.java @@ -26,6 +26,9 @@ import org.apache.logging.log4j.core.config.ConfigurationFileWatcher; import org.apache.logging.log4j.core.config.ConfigurationListener; import org.apache.logging.log4j.core.config.Reconfigurable; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.plugins.Namespace; +import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.model.PluginNamespace; import org.apache.logging.log4j.plugins.model.PluginType; import org.apache.logging.log4j.status.StatusLogger; @@ -33,13 +36,15 @@ /** * Creates Watchers of various types. */ +@Singleton public class WatcherFactory { private static final Logger LOGGER = StatusLogger.getLogger(); private final PluginNamespace plugins; - public WatcherFactory(final PluginNamespace watcherPlugins) { + @Inject + public WatcherFactory(@Namespace(Watcher.CATEGORY) final PluginNamespace watcherPlugins) { plugins = watcherPlugins; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java deleted file mode 100644 index a5458ea5ea4..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.util.internal; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.config.ConfigurationException; -import org.apache.logging.log4j.core.net.UrlConnectionFactory; -import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; -import org.apache.logging.log4j.core.util.AuthorizationProvider; -import org.apache.logging.log4j.status.StatusLogger; - -/** - * Utility method for reading data from an HTTP InputStream. - */ -public final class HttpInputStreamUtil { - - private static final Logger LOGGER = StatusLogger.getLogger(); - private static final int NOT_MODIFIED = 304; - private static final int NOT_AUTHORIZED = 401; - private static final int NOT_FOUND = 404; - private static final int OK = 200; - private static final int BUF_SIZE = 1024; - - public static Result getInputStream(final LastModifiedSource source, - final AuthorizationProvider authorizationProvider) { - final Result result = new Result(); - try { - long lastModified = source.getLastModified(); - HttpURLConnection connection = UrlConnectionFactory.createConnection(source.getURI().toURL(), - lastModified, SslConfigurationFactory.getSslConfiguration(), authorizationProvider); - connection.connect(); - try { - int code = connection.getResponseCode(); - switch (code) { - case NOT_MODIFIED: { - LOGGER.debug("Configuration not modified"); - result.status = Status.NOT_MODIFIED; - return result; - } - case NOT_FOUND: { - LOGGER.debug("Unable to access {}: Not Found", source.toString()); - result.status = Status.NOT_FOUND; - return result; - } - case OK: { - try (InputStream is = connection.getInputStream()) { - source.setLastModified(connection.getLastModified()); - LOGGER.debug("Content was modified for {}. previous lastModified: {}, new lastModified: {}", - source.toString(), lastModified, connection.getLastModified()); - result.status = Status.SUCCESS; - result.inputStream = new ByteArrayInputStream(readStream(is)); - return result; - } catch (final IOException e) { - try (InputStream es = connection.getErrorStream()) { - LOGGER.info("Error accessing configuration at {}: {}", source.toString(), - readStream(es)); - } catch (final IOException ioe) { - LOGGER.error("Error accessing configuration at {}: {}", source.toString(), - e.getMessage()); - } - throw new ConfigurationException("Unable to access " + source.toString(), e); - } - } - case NOT_AUTHORIZED: { - throw new ConfigurationException("Authorization failed"); - } - default: { - if (code < 0) { - LOGGER.info("Invalid response code returned"); - } else { - LOGGER.info("Unexpected response code returned {}", code); - } - throw new ConfigurationException("Unable to access " + source.toString()); - } - } - } finally { - connection.disconnect(); - } - } catch (IOException e) { - LOGGER.warn("Error accessing {}: {}", source.toString(), e.getMessage()); - throw new ConfigurationException("Unable to access " + source.toString(), e); - } - } - - public static byte[] readStream(final InputStream is) throws IOException { - final ByteArrayOutputStream result = new ByteArrayOutputStream(); - final byte[] buffer = new byte[BUF_SIZE]; - int length; - while ((length = is.read(buffer)) != -1) { - result.write(buffer, 0, length); - } - return result.toByteArray(); - } - - public static class Result { - - private InputStream inputStream; - private Status status; - - public Result() { - } - - public Result(Status status) { - this.status = status; - } - - public InputStream getInputStream() { - return inputStream; - } - - public Status getStatus() { - return status; - } - } -} diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/ThreadContextBenchmarkAccess.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpResponse.java similarity index 58% rename from log4j-perf/src/main/java/org/apache/logging/log4j/ThreadContextBenchmarkAccess.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpResponse.java index 129b8632101..f21560920bb 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/ThreadContextBenchmarkAccess.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpResponse.java @@ -14,21 +14,28 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j; +package org.apache.logging.log4j.core.util.internal; -/** - *

    - * Utility class to access package protected methods in {@code ThreadContext}. - *

    - * - * @see ThreadContext - * @since 2.7 - */ -public final class ThreadContextBenchmarkAccess { - private ThreadContextBenchmarkAccess() { // prevent instantiation +import java.io.InputStream; + +public class HttpResponse { + private final Status status; + private final InputStream inputStream; + + public HttpResponse(final Status status) { + this(status, InputStream.nullInputStream()); + } + + public HttpResponse(final Status status, final InputStream inputStream) { + this.status = status; + this.inputStream = inputStream; + } + + public Status getStatus() { + return status; } - public static void init() { - ThreadContext.init(); + public InputStream getInputStream() { + return inputStream; } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpSourceLoader.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpSourceLoader.java new file mode 100644 index 00000000000..126969b9b9e --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpSourceLoader.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.util.internal; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.ConfigurationException; +import org.apache.logging.log4j.core.net.UrlConnectionFactory; +import org.apache.logging.log4j.plugins.Inject; +import org.apache.logging.log4j.status.StatusLogger; + +public class HttpSourceLoader { + private static final int NOT_MODIFIED = 304; + private static final int NOT_AUTHORIZED = 401; + private static final int NOT_FOUND = 404; + private static final int OK = 200; + private final Logger logger = StatusLogger.getLogger(); + private final UrlConnectionFactory urlConnectionFactory; + + @Inject + public HttpSourceLoader(final UrlConnectionFactory urlConnectionFactory) { + this.urlConnectionFactory = urlConnectionFactory; + } + + public HttpResponse load(final LastModifiedSource source) { + final long lastModified = source.getLastModified(); + try { + final HttpURLConnection connection = urlConnectionFactory.openConnection(source.getURL(), lastModified); + connection.connect(); + try { + int code = connection.getResponseCode(); + switch (code) { + case NOT_MODIFIED: { + logger.debug("Configuration not modified"); + return new HttpResponse(Status.NOT_MODIFIED); + } + case NOT_FOUND: { + logger.debug("Unable to access {}: Not Found", source); + return new HttpResponse(Status.NOT_FOUND); + } + case OK: { + try (InputStream is = connection.getInputStream()) { + source.setLastModified(connection.getLastModified()); + logger.debug("Content was modified for {}. previous lastModified: {}, new lastModified: {}", + source, lastModified, connection.getLastModified()); + return new HttpResponse(Status.SUCCESS, new ByteArrayInputStream(is.readAllBytes())); + } catch (final IOException e) { + try (InputStream es = connection.getErrorStream()) { + logger.info("Error accessing configuration at {}: {}", source, es.readAllBytes()); + } catch (final IOException ioe) { + logger.error("Error accessing configuration at {}: {}", source, e.getMessage()); + } + throw new ConfigurationException("Unable to access " + source, e); + } + } + case NOT_AUTHORIZED: { + throw new ConfigurationException("Authorization failed"); + } + default: { + if (code < 0) { + logger.info("Invalid response code returned"); + } else { + logger.info("Unexpected response code returned {}", code); + } + throw new ConfigurationException("Unable to access " + source.toString()); + } + } + } finally { + connection.disconnect(); + } + } catch (IOException e) { + logger.warn("Error accessing {}: {}", source, e.getMessage()); + throw new ConfigurationException("Unable to access " + source, e); + } + } +} diff --git a/log4j-core/src/main/resources/META-INF/log4j2.default.component.json b/log4j-core/src/main/resources/META-INF/log4j2.default.component.json new file mode 100644 index 00000000000..e8cc8744ecb --- /dev/null +++ b/log4j-core/src/main/resources/META-INF/log4j2.default.component.json @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +{ + "log4j2": { + "*": { + "AsyncLogger": { + "discardThreshold": "INFO", + "exceptionHandler": null, + "formatMsgAsync": false, + "queueFullPolicy": "Default", + "ringBufferSize": "calculate", + "synchronizeEnqueueWhenQueueFull": true, + "threadNameStrategy": "CACHED", + "waitStrategy": "Timeout" + }, + "AsyncLoggerConfig": { + "exceptionHandler": null, + "ringBufferSize": "calculate", + "synchronizeEnqueueWhenQueueFull": true, + "waitStrategy": "Timeout" + }, + "Configuration": { + "allowedProtocols": [ + "https", + "file", + "jar" + ], + "clock": null, + /*"clock": "org.apache.logging.log4j.core.util.SystemClock",*/ + "factory": null, + /*"factory": "org.apache.logging.log4j.core.config.DefaultConfigurationFactory",*/ + "level": "ERROR", + "location": null, + "mergeStrategy": null, + /*"mergeStrategy": "org.apache.logging.log4j.core.config.composite.DefaultMergeStrategy",*/ + "reliabilityStrategy": "AwaitCompletion", + "reliabilityStrategyAwaitUnconditionallyMillis": 5000 + }, + "GC": { + "enableDirectEncoders": true, + "encoderByteBufferSize": 8192, + "encoderCharBufferSize": 2048, + "initialReusableMsgSize": 128, + "layoutStringBuilderMaxSize": 2048 + }, + "Jansi": { + "enabled": true + }, + "JMX": { + "enabled": false, + "notifyAsync": "calculate" + }, + "JNDI": { + "enableContextSelector": false, + "enableJdbc": false, + "enableJms": false, + "enableLookup": false + }, + "LoggerContext": { + "contextSelector": null, + /*"contextSelector": "org.apache.logging.log4j.core.selector.ClassLoaderContextSelector",*/ + "factory": null, + /*"factory": "org.apache.logging.log4j.core.impl.Log4jContextFactory",*/ + "logEventFactory": null, + /*"logEventFactory": "org.apache.logging.log4j.core.impl.DefaultLogEventFactory",*/ + "shutdownCallbackRegistry": null, + /*"shutdownCallbackRegistry": "org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry",*/ + "shutdownHookEnabled": true, + "stacktraceOnStart": false + }, + "Script": { + "enableLanguages": [] + }, + "StatusLogger": { + "defaultStatusLevel": "ERROR" + }, + "ThreadContext": { + "contextData": null, + "contextDataInjector": null + }, + "TransportSecurity": { + "authorizationProvider": null, + "keyStoreKeyManagerFactoryAlgorithm": null, + "keyStoreLocation": null, + "keyStorePassword": null, + "keyStorePasswordEnvironmentVariable": null, + "keyStorePasswordFile": null, + "keyStoreType": null, + "trustStoreKeyStoreType": null, + "trustStoreKeyManagerFactoryAlgorithm": null, + "trustStoreLocation": null, + "trustStorePassword": null, + "trustStorePasswordEnvironmentVariable": null, + "trustStorePasswordFile": null, + "verifyHostName": true + }, + "UUID": { + "sequence": 0 + } + } + } +} diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java index 788a070109e..6e33479fc4f 100644 --- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java +++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.flume.appender; -import java.io.Serializable; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ public static ManagerType getType(final String type) { } } - private FlumeAppender(final String name, final Filter filter, final Layout layout, + private FlumeAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, final String includes, final String excludes, final String required, final String mdcPrefix, final String eventPrefix, final boolean compress, final FlumeEventFactory factory, final Property[] properties, final AbstractFlumeManager manager) { @@ -212,7 +211,7 @@ public static FlumeAppender createAppender( @PluginAttribute final String batchSize, @PluginAttribute final String lockTimeoutRetries, @PluginElement final FlumeEventFactory factory, - @PluginElement Layout layout, + @PluginElement Layout layout, @PluginElement final Filter filter, final Injector injector) { diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java index 1e736f30ed9..14423096254 100644 --- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java +++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java @@ -30,8 +30,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.util.Patterns; import org.apache.logging.log4j.core.util.UuidUtil; @@ -48,10 +47,6 @@ public class FlumeEvent extends SimpleEvent implements LogEvent { static final String GUID = "guId"; - /** - * Generated serial version ID. - */ - private static final long serialVersionUID = -8988674608627854140L; private static final String DEFAULT_MDC_PREFIX = Strings.EMPTY; @@ -178,7 +173,7 @@ protected void addContextData(final String prefix, final Map fie @Override public LogEvent toImmutable() { - return Log4jLogEvent.createMemento(this); + return copy(); } /** diff --git a/log4j-gctests/src/test/java/org/apache/logging/log4j/gctests/GcFreeLoggingTestUtil.java b/log4j-gctests/src/test/java/org/apache/logging/log4j/gctests/GcFreeLoggingTestUtil.java index 169cf6ed669..c305526698d 100644 --- a/log4j-gctests/src/test/java/org/apache/logging/log4j/gctests/GcFreeLoggingTestUtil.java +++ b/log4j-gctests/src/test/java/org/apache/logging/log4j/gctests/GcFreeLoggingTestUtil.java @@ -31,7 +31,8 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.spi.LoggingSystemProperties; @@ -53,12 +54,12 @@ public static void executeLogging(final String configurationFile, final Class testClass) throws Exception { System.setProperty(LoggingSystemProperties.SYSTEM_THREAD_LOCALS_ENABLED, "true"); - System.setProperty("log4j2.enable.direct.encoders", "true"); - System.setProperty(LoggingSystemProperties.SYSTEM_IS_WEBAPP, "false"); - System.setProperty("log4j.configurationFile", configurationFile); + System.setProperty(Log4jProperties.GC_ENABLE_DIRECT_ENCODERS, "true"); + System.setProperty(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP, "false"); + System.setProperty(Log4jProperties.CONFIG_LOCATION, configurationFile); assertTrue(isThreadLocalsEnabled(), "Constants.ENABLE_THREADLOCALS"); - assertTrue(Constants.ENABLE_DIRECT_ENCODERS, "Constants.ENABLE_DIRECT_ENCODERS"); + assertTrue(GarbageFreeConfiguration.getDefaultConfiguration().isDirectEncodersEnabled(), "Constants.ENABLE_DIRECT_ENCODERS"); assertFalse(isWebApp(), "Constants.isWebApp()"); final MyCharSeq myCharSeq = new MyCharSeq(); diff --git a/log4j-jakarta-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java b/log4j-jakarta-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java index ac4dd494f5d..cf943a7067f 100644 --- a/log4j-jakarta-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java +++ b/log4j-jakarta-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java @@ -23,16 +23,14 @@ 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.core.config.plugins.PluginBuilderAttribute; -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; import org.apache.logging.log4j.core.layout.AbstractStringLayout; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.web.WebLoggerContextUtils; -import java.io.Serializable; - /** * Logs using the ServletContext's log method */ @@ -41,7 +39,7 @@ public class ServletAppender extends AbstractAppender { public static class Builder> extends AbstractAppender.Builder - implements org.apache.logging.log4j.core.util.Builder { + implements org.apache.logging.log4j.plugins.util.Builder { @PluginBuilderAttribute private boolean logThrowables; @@ -57,9 +55,9 @@ public ServletAppender build() { LOGGER.error("No servlet context is available"); return null; } - Layout layout = getLayout(); + Layout layout = getLayout(); if (layout == null) { - layout = PatternLayout.createDefaultLayout(); + layout = PatternLayout.createDefaultLayout(WebLoggerContextUtils.getWebLoggerContext(servletContext).getConfiguration()); } else if (!(layout instanceof AbstractStringLayout)) { LOGGER.error("Layout must be a StringLayout to log to ServletContext"); return null; @@ -85,7 +83,7 @@ public void setLogThrowables(final boolean logThrowables) { } - @PluginBuilderFactory + @PluginFactory public static > B newBuilder() { return new Builder().asBuilder(); } @@ -93,7 +91,7 @@ public static > B newBuilder() { private final ServletContext servletContext; private final boolean logThrowables; - private ServletAppender(final String name, final Layout layout, final Filter filter, + private ServletAppender(final String name, final Layout layout, final Filter filter, final ServletContext servletContext, final boolean ignoreExceptions, final boolean logThrowables) { super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY); this.servletContext = servletContext; @@ -110,23 +108,4 @@ public void append(final LogEvent event) { } } - /** - * Creates a Servlet Appender. - * @param layout The layout to use (required). Must extend {@link AbstractStringLayout}. - * @param filter The Filter or null. - * @param name The name of the Appender (required). - * @param ignoreExceptions If {@code true} (default) exceptions encountered when appending events are logged; - * otherwise they are propagated to the caller. - * @return The ServletAppender. - * @deprecated Use {@link #newBuilder()}. - */ - @Deprecated - public static ServletAppender createAppender(final Layout layout, final Filter filter, - final String name, final boolean ignoreExceptions) { - // @formatter:off - return newBuilder().setFilter(filter).setIgnoreExceptions(ignoreExceptions).setLayout(layout).setName(name) - .build(); - // @formatter:on - } - } diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java index ab65e2d963e..972bbb2e825 100644 --- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.jdbc.appender; +import java.sql.PreparedStatement; +import java.util.Arrays; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -32,10 +35,6 @@ import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.util.Assert; -import java.io.Serializable; -import java.sql.PreparedStatement; -import java.util.Arrays; - /** * This Appender writes logging events to a relational database using standard JDBC mechanisms. It takes a list of * {@link ColumnConfig}s and/or {@link ColumnMapping}s with which it determines how to save the event data into the @@ -185,7 +184,7 @@ public static > B newBuilder() { private final String description; - private JdbcAppender(final String name, final Filter filter, final Layout layout, + private JdbcAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, Property[] properties, final JdbcDatabaseManager manager) { super(name, filter, layout, ignoreExceptions, properties, manager); this.description = this.getName() + "{ manager=" + this.getManager() + " }"; diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java index 4477cf9ae10..bfcde7cdbb1 100644 --- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java @@ -16,25 +16,6 @@ */ package org.apache.logging.log4j.jdbc.appender; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.StringLayout; -import org.apache.logging.log4j.core.appender.AppenderLoggingException; -import org.apache.logging.log4j.core.appender.ManagerFactory; -import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager; -import org.apache.logging.log4j.core.appender.db.ColumnMapping; -import org.apache.logging.log4j.core.appender.db.DbAppenderLoggingException; -import org.apache.logging.log4j.core.util.Closer; -import org.apache.logging.log4j.core.util.Log4jThread; -import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; -import org.apache.logging.log4j.message.MapMessage; -import org.apache.logging.log4j.spi.ThreadContextMap; -import org.apache.logging.log4j.spi.ThreadContextStack; -import org.apache.logging.log4j.util.IndexedReadOnlyStringMap; -import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.util.Strings; - -import java.io.Serializable; import java.io.StringReader; import java.sql.Clob; import java.sql.Connection; @@ -56,6 +37,24 @@ import java.util.Objects; import java.util.concurrent.CountDownLatch; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.StringLayout; +import org.apache.logging.log4j.core.appender.AppenderLoggingException; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager; +import org.apache.logging.log4j.core.appender.db.ColumnMapping; +import org.apache.logging.log4j.core.appender.db.DbAppenderLoggingException; +import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.core.util.Log4jThread; +import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; +import org.apache.logging.log4j.message.MapMessage; +import org.apache.logging.log4j.spi.ThreadContextMap; +import org.apache.logging.log4j.spi.ThreadContextStack; +import org.apache.logging.log4j.util.IndexedReadOnlyStringMap; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.Strings; + /** * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC. */ @@ -74,7 +73,7 @@ private static final class FactoryData extends AbstractDatabaseManager.AbstractF private final long reconnectIntervalMillis; private final boolean truncateStrings; - protected FactoryData(final int bufferSize, final Layout layout, + protected FactoryData(final int bufferSize, final Layout layout, final ConnectionSource connectionSource, final String tableName, final ColumnConfig[] columnConfigs, final ColumnMapping[] columnMappings, final boolean immediateFail, final long reconnectIntervalMillis, final boolean truncateStrings) { @@ -390,7 +389,7 @@ private static JdbcDatabaseManagerFactory getFactory() { * @return a new or existing JDBC manager as applicable. */ public static JdbcDatabaseManager getManager(final String name, final int bufferSize, - final Layout layout, final ConnectionSource connectionSource, + final Layout layout, final ConnectionSource connectionSource, final String tableName, final ColumnConfig[] columnConfigs, final ColumnMapping[] columnMappings, final boolean immediateFail, final long reconnectIntervalMillis, final boolean truncateStrings) { return getManager(name, new FactoryData(bufferSize, layout, connectionSource, tableName, columnConfigs, @@ -726,7 +725,7 @@ private Object truncate(final String nameKey, Object value) { } @Override - protected void writeInternal(final LogEvent event, final Serializable serializable) { + protected void writeInternal(final LogEvent event, final Object serializable) { StringReader reader = null; try { if (!this.isRunning() || this.connection == null || this.connection.isClosed() || this.statement == null @@ -812,7 +811,7 @@ protected void writeInternal(final LogEvent event, final Serializable serializab } @Override - protected void writeThrough(final LogEvent event, final Serializable serializable) { + protected void writeThrough(final LogEvent event, final Object serializable) { this.connectAndStart(); try { try { diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java index 22142147d9f..077a305f2ab 100644 --- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java @@ -17,12 +17,18 @@ package org.apache.logging.log4j.jeromq.appender; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; 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.Configuration; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; @@ -32,11 +38,6 @@ import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.util.Strings; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - /** * Sends log events to one or more ZeroMQ (JeroMQ) endpoints. *

    @@ -64,7 +65,7 @@ public final class JeroMqAppender extends AbstractAppender { private int sendRcFalse; private int sendRcTrue; - private JeroMqAppender(final String name, final Filter filter, final Layout layout, + private JeroMqAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, final List endpoints, final long affinity, final long backlog, final boolean delayAttachOnConnect, final byte[] identity, final boolean ipv4Only, final long linger, final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, final int receiveTimeOut, @@ -86,6 +87,7 @@ public static JeroMqAppender createAppender( // @formatter:off @Required(message = "No name provided for JeroMqAppender") @PluginAttribute final String name, @PluginElement Layout layout, + @PluginConfiguration final Configuration configuration, @PluginElement final Filter filter, @PluginElement final Property[] properties, // Super attributes @@ -114,7 +116,7 @@ public static JeroMqAppender createAppender( // @formatter:on ) { if (layout == null) { - layout = PatternLayout.createDefaultLayout(); + layout = PatternLayout.createDefaultLayout(configuration); } List endpoints; if (properties == null) { @@ -140,7 +142,7 @@ public static JeroMqAppender createAppender( @Override public synchronized void append(final LogEvent event) { - final Layout layout = getLayout(); + final Layout layout = getLayout(); final byte[] formattedMessage = layout.toByteArray(event); if (manager.send(getLayout().toByteArray(event))) { sendRcTrue++; diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java index 68efcd35e1e..2971983fb01 100644 --- a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java @@ -17,6 +17,10 @@ package org.apache.logging.log4j.jms.appender; +import java.util.Properties; +import java.util.concurrent.TimeUnit; +import javax.jms.JMSException; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -33,11 +37,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import javax.jms.JMSException; -import java.io.Serializable; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - /** * Generic JMS Appender plugin for both queues and topics. This Appender replaces the previous split ones. However, * configurations set up for the 2.0 version of the JMS appenders will still work. @@ -219,7 +218,7 @@ public static Builder newBuilder() { * @throws JMSException * not thrown as of 2.9 but retained in the signature for compatibility, will be removed in 3.0. */ - protected JmsAppender(final String name, final Filter filter, final Layout layout, + protected JmsAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, Property[] properties, final JmsManager manager) throws JMSException { super(name, filter, layout, ignoreExceptions, properties); this.manager = manager; diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java index 2695096d24e..4e494c6f7bd 100644 --- a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java @@ -361,16 +361,18 @@ private Destination createDestination(final JndiManager jndiManager) throws Nami * @return A new JMS message containing the provided object. * @throws JMSException if an error occurs. */ - public Message createMessage(final Serializable object) throws JMSException { + public Message createMessage(final Object object) throws JMSException { if (object instanceof String) { return this.session.createTextMessage((String) object); } else if (object instanceof org.apache.logging.log4j.message.MapMessage) { return map((org.apache.logging.log4j.message.MapMessage) object, this.session.createMapMessage()); + } else if (object instanceof Serializable) { + return this.session.createObjectMessage((Serializable) object); } - return this.session.createObjectMessage(object); + throw new UnsupportedOperationException("Cannot create JMS message for object with type " + object.getClass()); } - private void createMessageAndSend(final LogEvent event, final Serializable serializable) throws JMSException { + private void createMessageAndSend(final LogEvent event, final Object serializable) throws JMSException { final Message message = createMessage(serializable); message.setJMSTimestamp(event.getTimeMillis()); messageProducer.send(message); @@ -453,7 +455,7 @@ protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { return closed && this.jndiManager.stop(timeout, timeUnit); } - void send(final LogEvent event, final Serializable serializable) { + void send(final LogEvent event, final Object serializable) { if (messageProducer == null) { if (reconnector != null && !configuration.isImmediateFail()) { reconnector.latch(); diff --git a/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java b/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java index 60c0577855c..6f18b35b22c 100644 --- a/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java +++ b/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java @@ -17,19 +17,9 @@ package org.apache.logging.log4j.jms.appender; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; - import java.io.Serializable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; @@ -40,9 +30,8 @@ import javax.jms.TextMessage; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.test.categories.Appenders; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.test.categories.Appenders; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.apache.logging.log4j.jndi.test.junit.JndiRule; import org.apache.logging.log4j.message.Message; @@ -55,6 +44,12 @@ import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; + @Category(Appenders.Jms.class) public class JmsAppenderTest { @@ -113,22 +108,22 @@ private Map createBindings() { return map; } - private Log4jLogEvent createLogEvent() { + private LogEvent createLogEvent() { return createLogEvent(new SimpleMessage(LOG_MESSAGE)); } - private Log4jLogEvent createLogEvent(final Message message) { + private LogEvent createLogEvent(final Message message) { // @formatter:off - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setLoggerName(JmsAppenderTest.class.getName()) .setLoggerFqcn(JmsAppenderTest.class.getName()) .setLevel(Level.INFO) .setMessage(message) - .build(); + .get(); // @formatter:on } - private Log4jLogEvent createMapMessageLogEvent() { + private LogEvent createMapMessageLogEvent() { final StringMapMessage mapMessage = new StringMapMessage(); return createLogEvent(mapMessage.with("testMesage", LOG_MESSAGE)); } diff --git a/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java b/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java index 074cb963b00..9b8689953fe 100644 --- a/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java +++ b/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java @@ -16,6 +16,14 @@ */ package org.apache.logging.log4j.jndi.selector; +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import javax.naming.NamingException; + import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.ContextAnchor; import org.apache.logging.log4j.core.selector.ContextSelector; @@ -25,16 +33,6 @@ import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.status.StatusLogger; -import javax.naming.NamingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; - /** * This class can be used to define a custom logger repository. It makes use of the fact that in J2EE environments, each * web-application is guaranteed to have its own JNDI context relative to the java:comp/env context. In @@ -90,7 +88,7 @@ @Singleton public class JndiContextSelector implements NamedContextSelector { - private static final LoggerContext CONTEXT = new LoggerContext("Default"); + private static final LoggerContext CONTEXT = LoggerContext.newBuilder().setName("Default").get(); private static final ConcurrentMap CONTEXT_MAP = new ConcurrentHashMap<>(); @@ -149,6 +147,16 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, fin return loggingContextName == null ? CONTEXT : locateContext(loggingContextName, null, configLocation); } + @Override + public LoggerContext getContext(final String fqcn, final String name, final ClassLoader loader, + final boolean currentContext, final URI configLocation) { + final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); + if (lc != null) { + return lc; + } + return locateContext(name, null, configLocation); + } + private String getContextName() { String loggingContextName = null; @@ -167,7 +175,11 @@ public LoggerContext locateContext(final String name, final Object externalConte return null; } if (!CONTEXT_MAP.containsKey(name)) { - final LoggerContext ctx = new LoggerContext(name, externalContext, configLocation); + final LoggerContext ctx = LoggerContext.newBuilder() + .setName(name) + .setExternalContext(externalContext) + .setConfigLocation(configLocation) + .get(); CONTEXT_MAP.putIfAbsent(name, ctx); } return CONTEXT_MAP.get(name); @@ -195,7 +207,7 @@ public LoggerContext removeContext(final String name) { @Override public List getLoggerContexts() { - return Collections.unmodifiableList(new ArrayList<>(CONTEXT_MAP.values())); + return List.copyOf(CONTEXT_MAP.values()); } } diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java index 91d1394056b..24a06268980 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java @@ -26,12 +26,11 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.AbstractLogEvent; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.jpa.converter.ContextDataAttributeConverter; -import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; /** *

    @@ -71,7 +70,6 @@ @MappedSuperclass @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class AbstractLogEventWrapperEntity implements LogEvent { - private static final long serialVersionUID = 1L; private final LogEvent wrappedEvent; @@ -80,7 +78,6 @@ public abstract class AbstractLogEventWrapperEntity implements LogEvent { * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an * entity. */ - @SuppressWarnings("unused") protected AbstractLogEventWrapperEntity() { this(new NullLogEvent()); } @@ -100,7 +97,7 @@ protected AbstractLogEventWrapperEntity(final LogEvent wrappedEvent) { @Override public LogEvent toImmutable() { - return Log4jLogEvent.createMemento(this); + return copy(); } /** @@ -338,7 +335,6 @@ public ReadOnlyStringMap getContextData() { */ private static class NullLogEvent extends AbstractLogEvent { - private static final long serialVersionUID = 1L; // Inherits everything } } diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java index 366ced6cab5..e04b24fc024 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.jpa.appender; -import java.util.Map; import javax.persistence.Basic; import javax.persistence.Convert; import javax.persistence.MappedSuperclass; @@ -26,9 +25,16 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.jpa.converter.*; +import org.apache.logging.log4j.jpa.converter.ContextMapAttributeConverter; +import org.apache.logging.log4j.jpa.converter.ContextStackAttributeConverter; +import org.apache.logging.log4j.jpa.converter.InstantAttributeConverter; +import org.apache.logging.log4j.jpa.converter.LevelAttributeConverter; +import org.apache.logging.log4j.jpa.converter.MarkerAttributeConverter; +import org.apache.logging.log4j.jpa.converter.MessageAttributeConverter; +import org.apache.logging.log4j.jpa.converter.StackTraceElementAttributeConverter; +import org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter; import org.apache.logging.log4j.message.Message; /** @@ -60,7 +66,6 @@ */ @MappedSuperclass public abstract class BasicLogEventEntity extends AbstractLogEventWrapperEntity { - private static final long serialVersionUID = 1L; /** * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java index bc074912bfb..120e8066fee 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java @@ -16,9 +16,7 @@ */ package org.apache.logging.log4j.jpa.appender; -import java.io.Serializable; import java.lang.reflect.Constructor; - import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; @@ -85,7 +83,7 @@ protected void connectAndStart() { } @Override - protected void writeInternal(final LogEvent event, final Serializable serializable) { + protected void writeInternal(final LogEvent event, final Object serializable) { if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null || this.transaction == null) { throw new AppenderLoggingException( diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java index a390baffbc3..26febdefa3b 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java @@ -23,15 +23,15 @@ import javax.persistence.Converter; import javax.persistence.PersistenceException; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.util.StringMap; -import org.apache.logging.log4j.util.Strings; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.logging.log4j.core.impl.ContextDataFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.StringMap; +import org.apache.logging.log4j.util.Strings; /** * A JPA 2.1 attribute converter for {@link ReadOnlyStringMap}s in @@ -43,7 +43,19 @@ */ @Converter(autoApply = false) public class ContextDataJsonAttributeConverter implements AttributeConverter { - static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private final ContextDataFactory contextDataFactory; + private final ObjectMapper objectMapper; + + public ContextDataJsonAttributeConverter() { + contextDataFactory = new DefaultContextDataFactory(); + objectMapper = new ObjectMapper(); + } + + public ContextDataJsonAttributeConverter(final ContextDataFactory contextDataFactory, + final ObjectMapper objectMapper) { + this.contextDataFactory = contextDataFactory; + this.objectMapper = objectMapper; + } @Override public String convertToDatabaseColumn(final ReadOnlyStringMap contextData) { @@ -52,13 +64,13 @@ public String convertToDatabaseColumn(final ReadOnlyStringMap contextData) { } try { - final JsonNodeFactory factory = OBJECT_MAPPER.getNodeFactory(); + final JsonNodeFactory factory = objectMapper.getNodeFactory(); final ObjectNode root = factory.objectNode(); contextData.forEach((key, value) -> { // we will cheat here and write the toString of the Object... meh, but ok. root.put(key, String.valueOf(value)); }); - return OBJECT_MAPPER.writeValueAsString(root); + return objectMapper.writeValueAsString(root); } catch (final Exception e) { throw new PersistenceException("Failed to convert contextData to JSON string.", e); } @@ -70,8 +82,8 @@ public ReadOnlyStringMap convertToEntityAttribute(final String s) { return null; } try { - final StringMap result = ContextDataFactory.createContextData(); - final ObjectNode root = (ObjectNode) OBJECT_MAPPER.readTree(s); + final StringMap result = contextDataFactory.createContextData(); + final ObjectNode root = (ObjectNode) objectMapper.readTree(s); final Iterator> entries = root.fields(); while (entries.hasNext()) { final Map.Entry entry = entries.next(); diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java index 638f0f1c5e7..0a381b89ac9 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java @@ -21,13 +21,13 @@ import java.sql.SQLException; import java.sql.Statement; -import org.apache.logging.log4j.core.test.categories.Appenders; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.test.categories.Appenders; import org.apache.logging.log4j.util.Strings; import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNull; @Category(Appenders.Jpa.class) public class JpaHsqldbAppenderTest extends AbstractJpaAppenderTest { @@ -109,7 +109,6 @@ public void testBadConstructorEntity02() { @SuppressWarnings("unused") public static class BadConstructorEntity1 extends TestBaseEntity { - private static final long serialVersionUID = 1L; public BadConstructorEntity1(final LogEvent wrappedEvent) { super(wrappedEvent); @@ -118,7 +117,6 @@ public BadConstructorEntity1(final LogEvent wrappedEvent) { @SuppressWarnings("unused") public static class BadConstructorEntity2 extends TestBaseEntity { - private static final long serialVersionUID = 1L; public BadConstructorEntity2() { super(null); diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java index dc83f8f92a1..8ed5d0355cb 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java @@ -21,12 +21,13 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.message.Message; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotSame; public class LogEventEntityTest { @@ -34,8 +35,6 @@ public class LogEventEntityTest { public void testToImmutable_AbstractLogEventWrapperEntity() { final LogEvent logEvent = new AbstractLogEventWrapperEntity() { - private static final long serialVersionUID = 2L; - @Override public ContextStack getContextStack() { return null; @@ -111,12 +110,12 @@ public long getTimeMillis() { return 0; } }; - Assert.assertNotSame(logEvent, logEvent.toImmutable()); + assertNotSame(logEvent, logEvent.toImmutable()); } @Test public void testToImmutable_TestBaseEntity() { final LogEvent logEvent = new TestBaseEntity(); - Assert.assertNotSame(logEvent, logEvent.toImmutable()); + assertNotSame(logEvent, logEvent.toImmutable()); } } diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java index ae85df12f15..def6b02877a 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java @@ -17,8 +17,6 @@ package org.apache.logging.log4j.jpa.appender; import java.util.Date; -import java.util.Map; - import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Convert; @@ -34,21 +32,19 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.jpa.appender.AbstractLogEventWrapperEntity; import org.apache.logging.log4j.jpa.converter.InstantAttributeConverter; import org.apache.logging.log4j.jpa.converter.LevelAttributeConverter; import org.apache.logging.log4j.jpa.converter.MessageAttributeConverter; import org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter; -import org.apache.logging.log4j.util.ReadOnlyStringMap; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; @Entity @Table(name = "jpaBaseLogEntry") public class TestBaseEntity extends AbstractLogEventWrapperEntity { - private static final long serialVersionUID = 2L; private long id = 0L; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java index 12a38c45e45..0ce0475dcd1 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java @@ -29,7 +29,6 @@ @Table(name = "jpaBasicLogEntry") @SuppressWarnings("unused") public class TestBasicEntity extends BasicLogEventEntity { - private static final long serialVersionUID = 2L; private long id = 0L; diff --git a/log4j-jpl/src/test/java/module-info.java b/log4j-jpl/src/test/java/module-info.java index 0fe97d58180..217a127c102 100644 --- a/log4j-jpl/src/test/java/module-info.java +++ b/log4j-jpl/src/test/java/module-info.java @@ -22,6 +22,7 @@ requires transitive org.apache.logging.log4j.core; requires org.apache.logging.log4j.core.test; requires org.hamcrest; + requires junit; provides java.lang.System.LoggerFinder with org.apache.logging.log4j.jpl.Log4jSystemLoggerFinder; } diff --git a/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java b/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java index 17575903b55..c0e17a1de8b 100644 --- a/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java +++ b/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.junit.After; import org.junit.Before; @@ -79,7 +79,7 @@ public void testLog() throws Exception { final List events = eventAppender.getEvents(); assertThat(events, hasSize(1)); final LogEvent event = events.get(0); - assertThat(event, instanceOf(Log4jLogEvent.class)); + assertThat(event, instanceOf(ImmutableLogEvent.class)); assertEquals(Level.INFO, event.getLevel()); assertEquals(LOGGER_NAME, event.getLoggerName()); assertEquals("Informative message here.", event.getMessage().getFormattedMessage()); @@ -92,7 +92,7 @@ public void testParameterizedLogging() { final List events = eventAppender.getEvents(); assertThat(events, hasSize(1)); final LogEvent event = events.get(0); - assertThat(event, instanceOf(Log4jLogEvent.class)); + assertThat(event, instanceOf(ImmutableLogEvent.class)); assertEquals(Level.INFO, event.getLevel()); assertEquals(LOGGER_NAME, event.getLoggerName()); assertEquals("Hello, World!", event.getMessage().getFormattedMessage()); @@ -106,7 +106,7 @@ public void testParameterizedLoggingWithThrowable() { final List events = eventAppender.getEvents(); assertThat(events, hasSize(1)); final LogEvent event = events.get(0); - assertThat(event, instanceOf(Log4jLogEvent.class)); + assertThat(event, instanceOf(ImmutableLogEvent.class)); assertEquals(Level.INFO, event.getLevel()); assertEquals(LOGGER_NAME, event.getLoggerName()); assertEquals("Hello, World!", event.getMessage().getFormattedMessage()); diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/WrappedLogger.java b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/WrappedLogger.java index e7e39698a01..ccd9d8e77e2 100644 --- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/WrappedLogger.java +++ b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/WrappedLogger.java @@ -33,7 +33,7 @@ class WrappedLogger extends ExtendedLoggerWrapper { private static final String FQCN = ApiLogger.class.getName(); WrappedLogger(final ExtendedLogger logger) { - super(logger, logger.getName(), logger.getMessageFactory()); + super(logger, logger.getName(), logger.getMessageFactory(), logger.getFlowMessageFactory()); } @Override diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java index 238a4061c66..4a96aa70bd5 100644 --- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java +++ b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java @@ -21,7 +21,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.jul.ApiLogger; import org.apache.logging.log4j.jul.LevelTranslator; import org.junit.Test; @@ -74,7 +74,7 @@ public void testLog() throws Exception { final List events = eventAppender.getEvents(); assertThat(events).hasSize(1); final LogEvent event = events.get(0); - assertThat(event).isInstanceOf(Log4jLogEvent.class); + assertThat(event).isInstanceOf(ImmutableLogEvent.class); assertThat(event.getLevel()).isEqualTo(Level.INFO); assertThat(event.getLoggerName()).isEqualTo(LOGGER_NAME); assertThat(event.getMessage().getFormattedMessage()).isEqualTo("Informative message here."); @@ -102,7 +102,7 @@ public void testAlteringLogFilter() throws Exception { final List events = eventAppender.getEvents(); assertThat(events).hasSize(1); final LogEvent event = events.get(0); - assertThat(event).isInstanceOf(Log4jLogEvent.class); + assertThat(event).isInstanceOf(ImmutableLogEvent.class); assertThat(event.getLevel()).isEqualTo(Level.INFO); assertThat(event.getLoggerName()).isEqualTo(LOGGER_NAME); assertThat(event.getMessage().getFormattedMessage()).isEqualTo("This is not the message you are looking for."); diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java index 1f7fe83a4a4..9cc60cd3041 100644 --- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java +++ b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.jul.test; -import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -100,7 +99,7 @@ public ListAppender(final String name) { raw = false; } - public ListAppender(final String name, final Filter filter, final Layout layout, + public ListAppender(final String name, final Filter filter, final Layout layout, final boolean newline, final boolean raw) { super(name, filter, layout, true, Property.EMPTY_ARRAY); this.newLine = newline; @@ -115,11 +114,11 @@ public ListAppender(final String name, final Filter filter, final Layout layout = getLayout(); + final Layout layout = getLayout(); if (layout == null) { if (event instanceof MutableLogEvent) { // must take snapshot or subsequent calls to logger.log() will modify this event - events.add(((MutableLogEvent) event).createMemento()); + events.add(event.copy()); } else { events.add(event); } @@ -172,7 +171,7 @@ void write(final byte[] bytes) { public boolean stop(final long timeout, final TimeUnit timeUnit) { setStopping(); super.stop(timeout, timeUnit, false); - final Layout layout = getLayout(); + final Layout layout = getLayout(); if (layout != null) { final byte[] bytes = layout.getFooter(); if (bytes != null) { @@ -219,7 +218,7 @@ public List getData() { } public static ListAppender createAppender(final String name, final boolean newLine, final boolean raw, - final Layout layout, final Filter filter) { + final Layout layout, final Filter filter) { return new ListAppender(name, filter, layout, newLine, raw); } @@ -233,7 +232,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private String name; private boolean entryPerNewLine; private boolean raw; - private Layout layout; + private Layout layout; private Filter filter; public Builder setName(@Required @PluginAttribute final String name) { @@ -251,7 +250,7 @@ public Builder setRaw(@PluginAttribute final boolean raw) { return this; } - public Builder setLayout(@PluginElement final Layout layout) { + public Builder setLayout(@PluginElement final Layout layout) { this.layout = layout; return this; } diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java index 9d5567d29d3..db921327a25 100644 --- a/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java +++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.kafka.appender; -import java.io.Serializable; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -69,7 +68,7 @@ public static class Builder> extends AbstractAppender.Build @SuppressWarnings("resource") @Override public KafkaAppender build() { - final Layout layout = getLayout(); + final Layout layout = getLayout(); if (layout == null) { AbstractLifeCycle.LOGGER.error("No layout provided for KafkaAppender"); return null; @@ -155,7 +154,7 @@ public static > B newBuilder() { private final KafkaManager manager; - private KafkaAppender(final String name, final Layout layout, final Filter filter, + private KafkaAppender(final String name, final Layout layout, final Filter filter, final boolean ignoreExceptions, final KafkaManager manager, final Property[] properties, final int retryCount) { super(name, filter, layout, ignoreExceptions, properties); diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java index e638482d3c5..58fd8f162f0 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java @@ -24,7 +24,6 @@ import java.time.Duration; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -36,7 +35,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.test.categories.Appenders; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; import org.apache.logging.log4j.message.SimpleMessage; @@ -47,11 +45,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; @Category(Appenders.Kafka.class) public class KafkaAppenderTest { @@ -75,13 +69,13 @@ public void close(final Duration timeout) { private static final String LOG_MESSAGE = "Hello, world!"; private static final String TOPIC_NAME = "kafka-topic"; - private static Log4jLogEvent createLogEvent() { - return Log4jLogEvent.newBuilder() + private static LogEvent createLogEvent() { + return LogEvent.builder() .setLoggerName(KafkaAppenderTest.class.getName()) .setLoggerFqcn(KafkaAppenderTest.class.getName()) .setLevel(Level.INFO) .setMessage(new SimpleMessage(LOG_MESSAGE)) - .build(); + .get(); } @BeforeClass diff --git a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java index f6ff82ab094..4155fe29696 100644 --- a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java @@ -16,12 +16,14 @@ */ package org.apache.logging.log4j.jackson.json; +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; import org.apache.logging.log4j.jackson.InstantMixIn; @@ -33,9 +35,6 @@ import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; -import com.fasterxml.jackson.databind.Module.SetupContext; -import com.fasterxml.jackson.databind.module.SimpleModule; - /** * Used to set up {@link SetupContext} from different {@link SimpleModule}s. *

    diff --git a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java index 7eacd23781a..4b5725a3de5 100644 --- a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; @@ -32,8 +33,10 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.impl.MutableLogEvent; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.test.BasicConfigurationFactory; import org.apache.logging.log4j.core.test.appender.ListAppender; @@ -147,13 +150,13 @@ private String prepareJsonForObjectMessageAsJsonObjectTests(final int value, fin final TestClass testClass = new TestClass(); testClass.setValue(value); // @formatter:off - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() + final var expected = LogEvent.builder() .setLoggerName("a.B") .setLoggerFqcn("f.q.c.n") .setLevel(Level.DEBUG) .setMessage(new ObjectMessage(testClass)) .setThreadName("threadName") - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); // @formatter:off final AbstractJacksonLayout layout = JsonLayout.newBuilder() .setCompact(true) @@ -164,7 +167,7 @@ private String prepareJsonForObjectMessageAsJsonObjectTests(final int value, fin } private String prepareJsonForStacktraceTests(final boolean stacktraceAsString) { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); // @formatter:off final AbstractJacksonLayout layout = JsonLayout.newBuilder() .setCompact(true) @@ -210,7 +213,7 @@ public void testMutableLogEvent() throws Exception { .setCharset(StandardCharsets.UTF_8) .setConfiguration(ctx.getConfiguration()) .build(); - Log4jLogEvent logEvent = LogEventFixtures.createLogEvent(); + var logEvent = LogEventFixtures.createLogEvent(); final MutableLogEvent mutableEvent = new MutableLogEvent(); mutableEvent.initFrom(logEvent); final String strLogEvent = layout.toSerializable(logEvent); @@ -221,7 +224,7 @@ public void testMutableLogEvent() throws Exception { private void testAllFeatures(final boolean locationInfo, final boolean compact, final boolean eventEol, final String endOfLine, final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) throws Exception { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); // @formatter:off final AbstractJacksonLayout layout = JsonLayout.newBuilder() .setLocationInfo(locationInfo) @@ -247,7 +250,7 @@ private void testAllFeatures(final boolean locationInfo, final boolean compact, } assertEquals(locationInfo, str.contains("source"), str); assertEquals(includeContext, str.contains("contextMap"), str); - final Log4jLogEvent actual = new Log4jJsonObjectMapper(contextMapAslist, includeStacktrace, false, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jJsonObjectMapper(contextMapAslist, includeStacktrace, false, false).readValue(str, ImmutableLogEvent.class); LogEventFixtures.assertEqualLogEvents(expected, actual, locationInfo, includeContext, includeStacktrace); if (includeContext) { this.checkMapEntry("MDC.A", "A_Value", compact, str, contextMapAslist); @@ -465,17 +468,17 @@ public void testLayoutLoggerName() throws Exception { .build(); // @formatter:on // @formatter:off - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() + final var expected = LogEvent.builder() .setLoggerName("a.B") .setLoggerFqcn("f.q.c.n") .setLevel(Level.DEBUG) .setMessage(new SimpleMessage("M")) .setThreadName("threadName") - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); // @formatter:on final String str = layout.toSerializable(expected); assertTrue(str.contains("\"loggerName\":\"a.B\""), str); - final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, ImmutableLogEvent.class); assertEquals(expected.getLoggerName(), actual.getLoggerName()); assertEquals(expected, actual); } @@ -493,17 +496,17 @@ public void testLayoutMessageWithCurlyBraces() throws Exception { .setCharset(StandardCharsets.UTF_8) .setIncludeStacktrace(true) .build(); - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() + final var expected = LogEvent.builder() .setLoggerName("a.B") .setLoggerFqcn("f.q.c.n") .setLevel(Level.DEBUG) .setMessage(new ParameterizedMessage("Testing {}", new TestObj())) .setThreadName("threadName") - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); final String str = layout.toSerializable(expected); final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; assertTrue(str.contains("\"message\":\"" + expectedMessage + '"'), str); - final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, ImmutableLogEvent.class); assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); } @@ -523,19 +526,19 @@ public void testReusableLayoutMessageWithCurlyBraces() throws Exception { .build(); Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj()); try { - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() + final var expected = LogEvent.builder() .setLoggerName("a.B") .setLoggerFqcn("f.q.c.n") .setLevel(Level.DEBUG) .setMessage(message) .setThreadName("threadName") - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); MutableLogEvent mutableLogEvent = new MutableLogEvent(); mutableLogEvent.initFrom(expected); final String str = layout.toSerializable(mutableLogEvent); final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; assertTrue(str.contains("\"message\":\"" + expectedMessage + '"'), str); - final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, ImmutableLogEvent.class); assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); } finally { ReusableMessageFactory.release(message); @@ -559,14 +562,17 @@ public void testLayoutRingBufferEventReusableMessageWithCurlyBraces() throws Exc Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj()); try { RingBufferLogEvent ringBufferEvent = new RingBufferLogEvent(); + ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + ContextDataInjector contextDataInjector = ThreadContextDataInjector.create(contextDataFactory); ringBufferEvent.setValues( null, "a.B", null, "f.q.c.n", Level.DEBUG, message, null, new SortedArrayStringMap(), ThreadContext.EMPTY_STACK, 1L, - "threadName", 1, null, new SystemClock(), new DummyNanoClock()); + "threadName", 1, null, new SystemClock(), new DummyNanoClock(), + contextDataFactory, contextDataInjector); final String str = layout.toSerializable(ringBufferEvent); final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; assertThat(str, containsString("\"message\":\"" + expectedMessage + '"')); - final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, ImmutableLogEvent.class); assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); } finally { ReusableMessageFactory.release(message); @@ -661,17 +667,16 @@ public void jsonLayout_should_substitute_lookups() { }; JsonLayout layout = JsonLayout .newBuilder() - .setConfiguration(new DefaultConfiguration()) + .setConfiguration(new DefaultConfiguration(ctx)) .setAdditionalFields(additionalFields) .build(); // Create a log event containing `WHO` key in MDC. - StringMap contextData = ContextDataFactory.createContextData(); + StringMap contextData = new SortedArrayStringMap(); contextData.putValue("WHO", "mduft"); - LogEvent logEvent = Log4jLogEvent - .newBuilder() + LogEvent logEvent = LogEvent.builder() .setContextData(contextData) - .build(); + .get(); // Verify the `WHO` key. String serializedLogEvent = layout.toSerializable(logEvent); diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java index 9d8687d6829..6a3ffb96f66 100644 --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java @@ -16,10 +16,17 @@ */ package org.apache.logging.log4j.jackson.xml; +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.jackson.AbstractLogEventMixIn; import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer; @@ -30,14 +37,6 @@ import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.ReadOnlyStringMap; -import com.fasterxml.jackson.annotation.JsonFilter; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; - /** *

    AbstractLogEventMixIn
     *├─ XmlLogEventMixIn
    @@ -68,8 +67,6 @@ public abstract class AbstractLogEventXmlMixIn extends AbstractLogEventMixIn {
     
         public static final String ELT_THROWN = "Thrown";
     
    -    private static final long serialVersionUID = 1L;
    -
         @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP)
         @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class)
         @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class)
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java
    index 04f1d3d5820..75cb9081119 100644
    --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java
    +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java
    @@ -16,13 +16,12 @@
      */
     package org.apache.logging.log4j.jackson.xml;
     
    -import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer;
    -import org.apache.logging.log4j.jackson.XmlConstants;
    -import org.apache.logging.log4j.util.ReadOnlyStringMap;
    -
     import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
     import com.fasterxml.jackson.databind.annotation.JsonSerialize;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
    +import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer;
    +import org.apache.logging.log4j.jackson.XmlConstants;
    +import org.apache.logging.log4j.util.ReadOnlyStringMap;
     
     /**
      * 
    @@ -37,8 +36,6 @@
      */
     public abstract class LogEventWithContextListXmlMixIn extends AbstractLogEventXmlMixIn {
     
    -    private static final long serialVersionUID = 1L;
    -
         @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP)
         @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class)
         @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class)
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java
    index 9cc85c349f4..609702107a4 100644
    --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java
    +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java
    @@ -17,14 +17,13 @@
     
     package org.apache.logging.log4j.jackson.xml;
     
    -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
    -import org.apache.logging.log4j.core.impl.ThrowableProxy;
    -import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn;
    -import org.apache.logging.log4j.jackson.XmlConstants;
    -
     import com.fasterxml.jackson.annotation.JsonIgnore;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
    +import org.apache.logging.log4j.core.ExtendedStackTraceElement;
    +import org.apache.logging.log4j.core.ThrowableProxy;
    +import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn;
    +import org.apache.logging.log4j.jackson.XmlConstants;
     
     public abstract class ThrowableProxyWithStacktraceAsStringXmlMixIn extends ThrowableProxyWithStacktraceAsStringMixIn {
     
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java
    index a4ef46792aa..167fb2eb291 100644
    --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java
    +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java
    @@ -16,14 +16,13 @@
      */
     package org.apache.logging.log4j.jackson.xml;
     
    -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
    -import org.apache.logging.log4j.core.impl.ThrowableProxy;
    -import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn;
    -import org.apache.logging.log4j.jackson.XmlConstants;
    -
     import com.fasterxml.jackson.annotation.JsonIgnore;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
    +import org.apache.logging.log4j.core.ExtendedStackTraceElement;
    +import org.apache.logging.log4j.core.ThrowableProxy;
    +import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn;
    +import org.apache.logging.log4j.jackson.XmlConstants;
     
     public abstract class ThrowableProxyWithoutStacktraceXmlMixIn extends ThrowableProxyWithoutStacktraceMixIn {
     
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java
    index b52f7f6be1c..141366a8b3e 100644
    --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java
    +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java
    @@ -17,14 +17,13 @@
     
     package org.apache.logging.log4j.jackson.xml;
     
    -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
    -import org.apache.logging.log4j.core.impl.ThrowableProxy;
    -import org.apache.logging.log4j.jackson.ThrowableProxyMixIn;
    -import org.apache.logging.log4j.jackson.XmlConstants;
    -
     import com.fasterxml.jackson.annotation.JsonIgnore;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
     import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
    +import org.apache.logging.log4j.core.ExtendedStackTraceElement;
    +import org.apache.logging.log4j.core.ThrowableProxy;
    +import org.apache.logging.log4j.jackson.ThrowableProxyMixIn;
    +import org.apache.logging.log4j.jackson.XmlConstants;
     
     public abstract class ThrowableProxyXmlMixIn extends ThrowableProxyMixIn {
     
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java
    index 51c26cfc6ea..2c825b64fbc 100644
    --- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java
    +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java
    @@ -16,17 +16,16 @@
      */
     package org.apache.logging.log4j.jackson.xml;
     
    +import com.fasterxml.jackson.databind.Module.SetupContext;
    +import com.fasterxml.jackson.databind.module.SimpleModule;
     import org.apache.logging.log4j.Level;
     import org.apache.logging.log4j.Marker;
    +import org.apache.logging.log4j.core.ExtendedStackTraceElement;
     import org.apache.logging.log4j.core.LogEvent;
    -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement;
    -import org.apache.logging.log4j.core.impl.ThrowableProxy;
    +import org.apache.logging.log4j.core.ThrowableProxy;
     import org.apache.logging.log4j.core.time.Instant;
     import org.apache.logging.log4j.jackson.LevelMixIn;
     
    -import com.fasterxml.jackson.databind.Module.SetupContext;
    -import com.fasterxml.jackson.databind.module.SimpleModule;
    -
     /**
      * Used to set up {@link SetupContext} from different {@link SimpleModule}s.
      * 

    diff --git a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java index b99806ec20e..ae77e1901c6 100644 --- a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java @@ -21,15 +21,19 @@ import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.impl.MutableLogEvent; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.test.BasicConfigurationFactory; @@ -49,10 +53,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; - import static org.junit.jupiter.api.Assertions.*; /** @@ -160,7 +160,7 @@ private void checkJsonPropertyOrder(final boolean includeContextStack, final boo } private String prepareXMLForStacktraceTests(final boolean stacktraceAsString) { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); // @formatter:off final AbstractJacksonLayout layout = XmlLayout.newBuilder() .setCompact(true) @@ -190,7 +190,7 @@ public void testMutableLogEvent() throws Exception { .setAdditionalFields(new KeyValuePair[] { new KeyValuePair("KEY1", "VALUE1"), new KeyValuePair("KEY2", "${java:runtime}"), }) .setCharset(StandardCharsets.UTF_8).setConfiguration(ctx.getConfiguration()).build(); - Log4jLogEvent logEvent = LogEventFixtures.createLogEvent(); + var logEvent = LogEventFixtures.createLogEvent(); final MutableLogEvent mutableEvent = new MutableLogEvent(); mutableEvent.initFrom(logEvent); final String strLogEvent = layout.toSerializable(logEvent); @@ -212,7 +212,7 @@ public void testMutableLogEvent() throws Exception { private void testAllFeatures(final boolean includeLocationInfo, final boolean compact, final boolean includeContextMap, final boolean includeContextStack, final boolean includeStacktrace) throws IOException, JsonParseException, JsonMappingException { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); // @formatter:off final XmlLayout layout = XmlLayout.newBuilder() .setLocationInfo(includeLocationInfo) @@ -228,7 +228,7 @@ private void testAllFeatures(final boolean includeLocationInfo, final boolean co assertEquals(!compact, str.contains("\n"), str); assertEquals(includeLocationInfo, str.contains("Source"), str); assertEquals(includeContextMap, str.contains("ContextMap"), str); - final Log4jLogEvent actual = new Log4jXmlObjectMapper().readValue(str, Log4jLogEvent.class); + final var actual = new Log4jXmlObjectMapper().readValue(str, ImmutableLogEvent.class); LogEventFixtures.assertEqualLogEvents(expected, actual, includeLocationInfo, includeContextMap, includeStacktrace); if (includeContextMap) { @@ -400,13 +400,13 @@ public void testLayoutLoggerName() { final XmlLayout layout = XmlLayout.newBuilder().setLocationInfo(false).setProperties(true).setComplete(true) .setCompact(false).setIncludeStacktrace(true).build(); - final Log4jLogEvent event = Log4jLogEvent.newBuilder() // + final var event = LogEvent.builder() // .setLoggerName("a.B") // .setLoggerFqcn("f.q.c.n") // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("M")) // .setThreadName("threadName") // - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); final String str = layout.toSerializable(event); assertTrue(str.contains("loggerName=\"a.B\""), str); } diff --git a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java index 89ade127a21..c70fc11a858 100644 --- a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java @@ -16,11 +16,13 @@ */ package org.apache.logging.log4j.jackson.yaml; +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; import org.apache.logging.log4j.jackson.InstantMixIn; @@ -32,9 +34,6 @@ import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; -import com.fasterxml.jackson.databind.Module.SetupContext; -import com.fasterxml.jackson.databind.module.SimpleModule; - /** * Used to set up {@link SetupContext} from different {@link SimpleModule}s. *

    diff --git a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java index 413ccf92cb7..7e919193844 100644 --- a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java @@ -23,11 +23,12 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.impl.MutableLogEvent; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.test.BasicConfigurationFactory; @@ -112,7 +113,7 @@ private void checkPropertyNameAbsent(final String name, final boolean compact, f } private String prepareYAMLForStacktraceTests(final boolean stacktraceAsString) { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); // @formatter:off final AbstractJacksonLayout layout = YamlLayout.newBuilder() .setIncludeStacktrace(true) @@ -151,7 +152,7 @@ public void testMutableLogEvent() throws Exception { .setCharset(StandardCharsets.UTF_8) .setConfiguration(ctx.getConfiguration()) .build(); - Log4jLogEvent logEvent = LogEventFixtures.createLogEvent(); + var logEvent = LogEventFixtures.createLogEvent(); final MutableLogEvent mutableEvent = new MutableLogEvent(); mutableEvent.initFrom(logEvent); final String strLogEvent = layout.toSerializable(logEvent); @@ -161,7 +162,7 @@ public void testMutableLogEvent() throws Exception { private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol, final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) throws Exception { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + final var expected = LogEventFixtures.createLogEvent(); final AbstractJacksonLayout layout = YamlLayout.newBuilder() .setLocationInfo(includeSource) .setProperties(includeContext) @@ -174,7 +175,7 @@ private void testAllFeatures(final boolean includeSource, final boolean compact, assertEquals(!compact || eventEol, str.contains("\n"), str); assertEquals(includeSource, str.contains("source"), str); assertEquals(includeContext, str.contains("contextMap"), str); - final Log4jLogEvent actual = new Log4jYamlObjectMapper(contextMapAslist, includeStacktrace,false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jYamlObjectMapper(contextMapAslist, includeStacktrace,false).readValue(str, ImmutableLogEvent.class); LogEventFixtures.assertEqualLogEvents(expected, actual, includeSource, includeContext, includeStacktrace); if (includeContext) { this.checkMapEntry("MDC.A", "A_Value", compact, str); @@ -357,16 +358,16 @@ public void testLayoutLoggerName() throws Exception { .setIncludeStacktrace(true) .setCharset(StandardCharsets.UTF_8) .build(); - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() // + final var expected = LogEvent.builder() // .setLoggerName("a.B") // .setLoggerFqcn("f.q.c.n") // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("M")) // .setThreadName("threadName") // - .setTimeMillis(1).build(); + .setTimeMillis(1).get(); final String str = layout.toSerializable(expected); assertThat(str, containsString("loggerName: \"a.B\"")); - final Log4jLogEvent actual = new Log4jYamlObjectMapper(false, true, false).readValue(str, Log4jLogEvent.class); + final var actual = new Log4jYamlObjectMapper(false, true, false).readValue(str, ImmutableLogEvent.class); assertEquals(expected.getLoggerName(), actual.getLoggerName()); assertEquals(expected, actual); } diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java index ba56e3f1679..360352a601d 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java @@ -19,13 +19,12 @@ import java.util.HashSet; import java.util.Set; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; - import com.fasterxml.jackson.core.PrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; public abstract class AbstractJacksonFactory { @@ -75,7 +74,7 @@ public ObjectWriter newWriter(final boolean locationInfo, final boolean properti except.add(getPropertyNameForTimeMillis()); } except.add(this.getPropertyNameForNanoTime()); - filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except)); + filters.addFilter(ImmutableLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except)); final ObjectWriter writer = this.newObjectMapper() .writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter()); return writer.with(filters); diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java index bbddb7acf89..e3f8c10e33f 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java @@ -23,25 +23,24 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.ObjectWriter; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.plugins.PluginBuilderAttribute; -import org.apache.logging.log4j.plugins.PluginElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.layout.AbstractStringLayout; import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.core.util.StringBuilderWriter; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.Strings; -import com.fasterxml.jackson.databind.ObjectWriter; - public abstract class AbstractJacksonLayout extends AbstractStringLayout { public static abstract class Builder> extends AbstractStringLayout.Builder { diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java index 059c09df943..5a2ac6a59e0 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java @@ -16,13 +16,12 @@ */ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.message.Message; - import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.message.Message; /** *

    @@ -47,9 +46,7 @@ public abstract class AbstractLogEventMixIn implements LogEvent {
         public static final String ATTR_THREAD_ID = "threadId";
         public static final String ATTR_THREAD_PRIORITY = "threadPriority";
         public static final String ELT_MESSAGE = "message";
    -    public static final String JSON_FILTER_ID = "org.apache.logging.log4j.core.impl.Log4jLogEvent";
    -
    -    private static final long serialVersionUID = 1L;
    +    public static final String JSON_FILTER_ID = "org.apache.logging.log4j.core.impl.ImmutableLogEvent";
     
         @JsonSerialize(using = MessageSerializer.class)
         @JsonDeserialize(using = SimpleMessageDeserializer.class)
    diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
    index 6efee4f37aa..861688ccdfa 100644
    --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
    +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java
    @@ -20,24 +20,28 @@
     import java.util.List;
     import java.util.Map;
     
    -import org.apache.logging.log4j.core.impl.ContextDataFactory;
    -import org.apache.logging.log4j.util.StringMap;
    -
     import com.fasterxml.jackson.core.JsonParser;
     import com.fasterxml.jackson.core.JsonProcessingException;
     import com.fasterxml.jackson.core.type.TypeReference;
     import com.fasterxml.jackson.databind.DeserializationContext;
     import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
    +import org.apache.logging.log4j.core.impl.ContextDataFactory;
    +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory;
    +import org.apache.logging.log4j.util.InternalApi;
    +import org.apache.logging.log4j.util.StringMap;
     
     /**
      * 

    * Consider this class private. *

    */ +@InternalApi public class ContextDataAsEntryListDeserializer extends StdDeserializer { private static final long serialVersionUID = 1L; + private final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + ContextDataAsEntryListDeserializer() { super(Map.class); } @@ -48,7 +52,7 @@ public StringMap deserialize(final JsonParser jp, final DeserializationContext c final List list = jp.readValueAs(new TypeReference>() { // do nothing }); - final StringMap contextData = ContextDataFactory.createContextData(); + final StringMap contextData = contextDataFactory.createContextData(); for (final MapEntry mapEntry : list) { contextData.putValue(mapEntry.getKey(), mapEntry.getValue()); } diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java index 9d6843ad791..902f6535845 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java @@ -1,4 +1,3 @@ - /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -20,24 +19,28 @@ import java.io.IOException; import java.util.Map; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.util.StringMap; - import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.apache.logging.log4j.core.impl.ContextDataFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; +import org.apache.logging.log4j.util.InternalApi; +import org.apache.logging.log4j.util.StringMap; /** *

    * Consider this class private. *

    */ +@InternalApi public class ContextDataDeserializer extends StdDeserializer { private static final long serialVersionUID = 1L; + private final ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + ContextDataDeserializer() { super(Map.class); } @@ -51,7 +54,7 @@ public StringMap deserialize(final JsonParser jp, final DeserializationContext c // if (tok != JsonToken.START_OBJECT) { // throw new IOException("Expected data to start with an Object"); // } - final StringMap contextData = ContextDataFactory.createContextData(); + final StringMap contextData = contextDataFactory.createContextData(); // Iterate over object fields: while (jp.nextToken() != JsonToken.END_OBJECT) { final String fieldName = jp.getCurrentName(); diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java index ea1dabe396e..6c265abf7e2 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java @@ -18,14 +18,12 @@ import java.io.Serializable; -import org.apache.logging.log4j.core.impl.ExtendedClassInfo; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ExtendedClassInfo; /** * Mix-in for {@link ExtendedStackTraceElement}. diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java index 034c40a43bf..de327a79120 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java @@ -16,15 +16,6 @@ */ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.util.ReadOnlyStringMap; - import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -32,9 +23,17 @@ import com.fasterxml.jackson.annotation.JsonRootName; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; @JsonRootName(JsonConstants.ELT_EVENT) -@JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent") +@JsonFilter("org.apache.logging.log4j.core.impl.ImmutableLogEvent") @JsonPropertyOrder({ // @formatter:off "timeMillis", @@ -57,8 +56,6 @@ */ public abstract class LogEventJsonMixIn /* extends AbstractLogEventMixIn */ implements LogEvent { - private static final long serialVersionUID = 1L; - @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) @JsonSerialize(using = ContextDataSerializer.class) @JsonDeserialize(using = ContextDataDeserializer.class) diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java index 2c26489cfe7..a0fe19c0ae9 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java @@ -16,15 +16,6 @@ */ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ThrowableProxy; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.util.ReadOnlyStringMap; - import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -32,15 +23,21 @@ import com.fasterxml.jackson.annotation.JsonRootName; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; @JsonRootName(XmlConstants.ELT_EVENT) -@JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent") +@JsonFilter("org.apache.logging.log4j.core.impl.ImmutableLogEvent") @JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP, JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" }) abstract class LogEventWithContextListMixIn implements LogEvent { - private static final long serialVersionUID = 1L; - @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) @JsonSerialize(using = ContextDataAsEntryListSerializer.class) @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java index 7f2b1df4e7d..0c7cb1672bb 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java @@ -16,16 +16,15 @@ */ package org.apache.logging.log4j.jackson; +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; -import com.fasterxml.jackson.databind.Module.SetupContext; -import com.fasterxml.jackson.databind.module.SimpleModule; - /** * Used to set up {@link SetupContext} from different {@link SimpleModule}s. *

    diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java index 7116c8099c1..fd2ad0e2311 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java @@ -17,11 +17,10 @@ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.ThrowableProxy; /** * Mix-in for {@link ThrowableProxy}. diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java index e73a108433c..83015b6d0c2 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java @@ -17,14 +17,13 @@ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.ThrowableProxy; /** - * Mix-in for {@link org.apache.logging.log4j.core.impl.ThrowableProxy}. + * Mix-in for {@link ThrowableProxy}. */ public abstract class ThrowableProxyWithStacktraceAsStringMixIn { diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java index b80c89ce952..b52e9a42b24 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java @@ -16,11 +16,10 @@ */ package org.apache.logging.log4j.jackson; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.logging.log4j.core.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.ThrowableProxy; /** * Mix-in for {@link ThrowableProxy}. diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java index d85fdba90b6..20eb56d52a6 100644 --- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java @@ -40,25 +40,24 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectWriter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.plugins.PluginBuilderAttribute; -import org.apache.logging.log4j.plugins.PluginElement; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ImmutableLogEvent; import org.apache.logging.log4j.core.layout.AbstractStringLayout; import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.core.util.StringBuilderWriter; import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.util.Strings; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonRootName; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectWriter; - abstract class AbstractJacksonLayout extends AbstractStringLayout { public static abstract class Builder> extends AbstractStringLayout.Builder { @@ -254,10 +253,10 @@ protected static class ResolvableKeyValuePair { protected static final String COMPACT_EOL = Strings.EMPTY; private static LogEvent convertMutableToLog4jEvent(final LogEvent event) { - // TODO Jackson-based layouts have certain filters set up for Log4jLogEvent. + // TODO Jackson-based layouts have certain filters set up for ImmutableLogEvent. // TODO Need to set up the same filters for MutableLogEvent but don't know how... // This is a workaround. - return event instanceof Log4jLogEvent ? event : Log4jLogEvent.createMemento(event); + return event instanceof ImmutableLogEvent ? event : event.copy(); } private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config, final KeyValuePair[] additionalFields) { diff --git a/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java index ee077118071..ca4e8aa7ee0 100644 --- a/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java +++ b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java @@ -16,15 +16,14 @@ */ package org.apache.logging.log4j.jackson; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - import java.io.IOException; -import org.apache.logging.log4j.core.impl.ThrowableProxy; - import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.core.ThrowableProxy; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; /** * diff --git a/log4j-layout-template-json-test/src/main/java/org/apache/logging/log4j/layout/template/json/LogEventFixture.java b/log4j-layout-template-json-test/src/main/java/org/apache/logging/log4j/layout/template/json/LogEventFixture.java index c2fd5c5285b..2481fc373ac 100644 --- a/log4j-layout-template-json-test/src/main/java/org/apache/logging/log4j/layout/template/json/LogEventFixture.java +++ b/log4j-layout-template-json-test/src/main/java/org/apache/logging/log4j/layout/template/json/LogEventFixture.java @@ -16,20 +16,20 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ContextDataFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.MutableThreadContextStack; import org.apache.logging.log4j.spi.ThreadContextStack; +import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - final class LogEventFixture { private LogEventFixture() {} @@ -54,8 +54,7 @@ private static LogEvent createLiteLogEvent(final String id, final long timeMilli final String loggerFqcn = "f.q.c.n" + id; final String loggerName = "a.B" + id; final long nanoTime = timeMillis * 2; - return Log4jLogEvent - .newBuilder() + return LogEvent.builder() .setLoggerName(loggerName) .setLoggerFqcn(loggerFqcn) .setLevel(level) @@ -114,8 +113,7 @@ private static LogEvent createFullLogEvent( final long nanoTime = timeMillis * 2; // Create the event. - return Log4jLogEvent - .newBuilder() + return LogEvent.builder() .setLoggerName(loggerName) .setLoggerFqcn(loggerFqcn) .setLevel(level) @@ -134,12 +132,12 @@ private static LogEvent createFullLogEvent( } private static StringMap createContextData(final String id) { - final StringMap contextData = ContextDataFactory.createContextData(); - contextData.putValue("MDC.String." + id, "String"); - contextData.putValue("MDC.BigDecimal." + id, BigDecimal.valueOf(Math.PI)); - contextData.putValue("MDC.Integer." + id, 10); - contextData.putValue("MDC.Long." + id, Long.MAX_VALUE); - return contextData; + return new SortedArrayStringMap(Map.of( + "MDC.String." + id, "String", + "MDC.BigDecimal." + id, BigDecimal.valueOf(Math.PI), + "MDC.Integer." + id, 10, + "MDC.Long." + id, Long.MAX_VALUE + )); } private static ThreadContextStack createContextStack(final String id) { diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutAdditionalFieldTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutAdditionalFieldTest.java index e5580f4172f..351a9497fb4 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutAdditionalFieldTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutAdditionalFieldTest.java @@ -16,22 +16,22 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.test.junit.Named; -import org.apache.logging.log4j.core.util.JsonReader; +import org.apache.logging.log4j.util.JsonReader; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - @Execution(ExecutionMode.SAME_THREAD) class JsonTemplateLayoutAdditionalFieldTest { diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java index a1a53a4d4d3..7cd391ccd01 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java @@ -42,6 +42,9 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; @@ -49,7 +52,6 @@ import org.apache.logging.log4j.core.appender.SocketAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.ByteBufferDestination; import org.apache.logging.log4j.core.lookup.MainMapLookup; import org.apache.logging.log4j.core.net.Severity; @@ -76,10 +78,6 @@ import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.ObjectMapper; - import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -212,8 +210,7 @@ void test_inline_template() { final int instantEpochSecondsNanos = instantAccessor.get(ChronoField.NANO_OF_SECOND); final MutableInstant instant = new MutableInstant(); instant.initFromEpochSecond(instantEpochSeconds, instantEpochSecondsNanos); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(message) @@ -270,8 +267,7 @@ void test_log4j_deferred_runtime_resolver_for_MapMessage() { .with("key1", "val1") .with("key2", "val2") .with("key3", Collections.singletonMap("foo", "bar")); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(mapMessage) @@ -293,8 +289,7 @@ void test_property_injection() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(message) @@ -329,8 +324,7 @@ void test_empty_root_cause() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); final RuntimeException exception = new RuntimeException("failure for test purposes"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.ERROR) .setMessage(message) @@ -395,8 +389,7 @@ void test_root_cause() { final SimpleMessage message = new SimpleMessage("Hello, World!"); final RuntimeException exceptionCause = new RuntimeException("failure cause for test purposes"); final RuntimeException exception = new RuntimeException("failure for test purposes", exceptionCause); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.ERROR) .setMessage(message) @@ -460,8 +453,7 @@ void test_marker_name() { final SimpleMessage message = new SimpleMessage("Hello, World!"); final String markerName = "test"; final Marker marker = MarkerManager.getMarker(markerName); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.ERROR) .setMessage(message) @@ -497,8 +489,7 @@ void test_lineSeparator_suffix() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(message) @@ -541,8 +532,7 @@ void test_main_key_access() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(message) @@ -618,8 +608,7 @@ stackTraceFieldName, asMap( final SimpleMessage message = new SimpleMessage("Hello, World!"); final RuntimeException exceptionCause = new RuntimeException("failure cause for test purposes"); final RuntimeException exception = new RuntimeException("failure for test purposes", exceptionCause); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.ERROR) .setMessage(message) @@ -724,8 +713,7 @@ void test_maxStringLength() { final String excessiveMessageString = Strings.repeat("m", maxStringLength) + 'M'; final SimpleMessage message = new SimpleMessage(excessiveMessageString); final Throwable thrown = new RuntimeException(); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(Level.INFO) .setMessage(message) @@ -778,8 +766,7 @@ void test_event_template_additional_fields() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); final Level level = Level.ERROR; - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(level) .setMessage(message) @@ -894,8 +881,7 @@ void test_timestamp_epoch_resolvers() { : (int) instantSecsObject; final int instantSecsNanos = (int) testCase.get("epochSecsNanos"); instant.initFromEpochSecond(instantSecs, instantSecsNanos); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(level) .setMessage(message) @@ -969,8 +955,7 @@ private static LogEvent createLogEventAtInstant(final String formattedInstant) { final long instantEpochMillis = Instant.parse(formattedInstant).toEpochMilli(); final MutableInstant instant = new MutableInstant(); instant.initFromEpochMilli(instantEpochMillis, 0); - return Log4jLogEvent - .newBuilder() + return LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setInstant(instant) @@ -1002,8 +987,7 @@ void test_level_severity() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setLevel(level) .setMessage(message) @@ -1027,8 +1011,7 @@ void test_exception_resolvers_against_no_exceptions() { // Create the log event. final SimpleMessage message = new SimpleMessage("Hello, World!"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build(); @@ -1095,8 +1078,7 @@ void test_inline_stack_trace_element_template() { // Create the log event. final Throwable error = new RuntimeException("foo"); final SimpleMessage message = new SimpleMessage("foo"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setThrown(error) @@ -1126,8 +1108,7 @@ void test_custom_resolver() { // Create the log event. final SimpleMessage message = new SimpleMessage("foo"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build(); @@ -1197,8 +1178,7 @@ void test_null_eventDelimiter() { // Create the log event. final SimpleMessage message = new SimpleMessage("foo"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build(); @@ -1281,8 +1261,7 @@ void test_against_SocketAppender() throws Exception { private static List createNastyLogEvents() { return createNastyMessages() .stream() - .map(message -> Log4jLogEvent - .newBuilder() + .map(message -> LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build()) @@ -1413,8 +1392,7 @@ void test_PatternResolver() { // Create the log event. final SimpleMessage message = new SimpleMessage("foo"); final Level level = Level.FATAL; - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setLevel(level) @@ -1481,8 +1459,7 @@ private static void testMessageParameterResolver(final MessageFactory messageFac final Object[] parameters = {1L + (long) Integer.MAX_VALUE, "foo", 56}; final Message message = messageFactory.newMessage("foo", parameters); final Level level = Level.FATAL; - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setLevel(level) @@ -1524,8 +1501,7 @@ private static void testMessageParameterResolverNoParameters( // Create the log event. final Message message = messageFactory.newMessage("foo", new Object[0]); final Level level = Level.FATAL; - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setLevel(level) @@ -1581,8 +1557,7 @@ void test_unresolvable_nested_fields_are_skipped() { // Create the log event. final SimpleMessage message = new SimpleMessage("foo"); final Exception thrown = new RuntimeException("bar"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .setThrown(thrown) @@ -1616,8 +1591,7 @@ void test_recursive_collections() { // Create the log event. final Message message = new ObjectMessage(recursiveCollection); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build(); @@ -1645,8 +1619,7 @@ void test_eventTemplateRootObjectKey() { // Create the log event. final Message message = new SimpleMessage("LOG4J2-2985"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setLoggerName(LOGGER_NAME) .setMessage(message) .build(); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java index 9e460f6e5fc..8b94d2abd0c 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java @@ -16,6 +16,23 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import co.elastic.logging.log4j2.EcsLayout; import org.apache.http.HttpHost; import org.apache.logging.log4j.Level; @@ -24,13 +41,12 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.SocketAppender; import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.GelfLayout; import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField; -import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecyclerFactory; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.RecyclerFactories; import org.assertj.core.api.Assertions; import org.awaitility.Awaitility; import org.elasticsearch.ElasticsearchStatusException; @@ -52,23 +68,6 @@ import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - @Execution(ExecutionMode.SAME_THREAD) class LogstashIT { @@ -123,7 +122,7 @@ class LogstashIT { .setConfiguration(CONFIGURATION) .setCharset(CHARSET) .setEventTemplateUri("classpath:EcsLayout.json") - .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance()) + .setRecyclerFactory(RecyclerFactories.ofSpec(null)) .setEventTemplateAdditionalFields( new EventTemplateAdditionalField[]{ EventTemplateAdditionalField @@ -239,8 +238,7 @@ void test_newlines() throws IOException { final String loggerName = "A"; final SimpleMessage message1 = new SimpleMessage("line1\nline2\r\nline3"); final long instantMillis1 = Instant.EPOCH.toEpochMilli(); - final LogEvent logEvent1 = Log4jLogEvent - .newBuilder() + final LogEvent logEvent1 = LogEvent.builder() .setLoggerName(loggerName) .setLoggerFqcn(loggerFqcn) .setLevel(level) @@ -249,8 +247,7 @@ void test_newlines() throws IOException { .build(); final SimpleMessage message2 = new SimpleMessage("line4\nline5\r\nline6"); final long instantMillis2 = instantMillis1 + Duration.ofDays(1).toMillis(); - final LogEvent logEvent2 = Log4jLogEvent - .newBuilder() + final LogEvent logEvent2 = LogEvent.builder() .setLoggerName(loggerName) .setLoggerFqcn(loggerFqcn) .setLevel(level) diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java index 5880d292a6c..ec9702269fd 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -27,14 +32,9 @@ import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; import org.apache.logging.log4j.core.test.appender.ListAppender; -import org.apache.logging.log4j.core.util.JsonReader; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; import org.apache.logging.log4j.layout.template.json.util.MapAccessor; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; +import org.apache.logging.log4j.util.JsonReader; public final class TestHelpers { diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java index ec97185074d..3a93620eb4a 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java @@ -21,7 +21,7 @@ import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.test.junit.Named; -import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecycler; +import org.apache.logging.log4j.util.ThreadLocalRecycler; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolverTest.java index fd51eda52d6..0233c11125d 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolverTest.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.layout.template.json.resolver; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; @@ -25,11 +24,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.apache.logging.log4j.layout.template.json.TestHelpers.CONFIGURATION; -import static org.apache.logging.log4j.layout.template.json.TestHelpers.asMap; -import static org.apache.logging.log4j.layout.template.json.TestHelpers.readJson; -import static org.apache.logging.log4j.layout.template.json.TestHelpers.usingSerializedLogEventAccessor; -import static org.apache.logging.log4j.layout.template.json.TestHelpers.writeJson; +import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -73,8 +68,7 @@ void test_upper( // Create the log event. final StringMap contextData = new SortedArrayStringMap(); contextData.putValue("input", input); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setContextData(contextData) .build(); @@ -125,7 +119,7 @@ void test_errorHandlingStrategy( .build(); // Create the log event. - final LogEvent logEvent = Log4jLogEvent.newBuilder().build(); + final LogEvent logEvent = LogEvent.builder().get(); // Check the serialized event. final boolean failureExpected = Strings.isNotBlank(failureMessage); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java index 3b6b9586ab5..fd31e7f636e 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java @@ -16,14 +16,13 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; +import java.math.BigInteger; + import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.util.JsonReader; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; +import org.apache.logging.log4j.util.JsonReader; import org.junit.jupiter.api.Test; -import java.math.BigInteger; - import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; @@ -141,7 +140,7 @@ private static void verify( .build(); // Create the log event. - final LogEvent logEvent = Log4jLogEvent.newBuilder().build(); + final LogEvent logEvent = LogEvent.builder().get(); // Check the 1st serialized event. final String serializedLogEvent1 = layout.toSerializable(logEvent); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolverTest.java index 999a6862e68..6a06fc69bfc 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolverTest.java @@ -16,27 +16,26 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.test.junit.Named; -import org.apache.logging.log4j.core.util.JsonReader; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ObjectMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.message.StringMapMessage; +import org.apache.logging.log4j.util.JsonReader; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; @@ -104,8 +103,7 @@ void test_message_fallbackKey() { // Create a log event with a MapMessage. final Message mapMessage = new StringMapMessage() .with("key1", "val1"); - final LogEvent mapMessageLogEvent = Log4jLogEvent - .newBuilder() + final LogEvent mapMessageLogEvent = LogEvent.builder() .setMessage(mapMessage) .setTimeMillis(System.currentTimeMillis()) .build(); @@ -117,8 +115,7 @@ void test_message_fallbackKey() { // Create a log event with a SimpleMessage. final Message simpleMessage = new SimpleMessage("simple"); - final LogEvent simpleMessageLogEvent = Log4jLogEvent - .newBuilder() + final LogEvent simpleMessageLogEvent = LogEvent.builder() .setMessage(simpleMessage) .setTimeMillis(System.currentTimeMillis()) .build(); @@ -137,8 +134,7 @@ void test_StringMapMessage() { final StringMapMessage message = new StringMapMessage(); message.put("message", "Hello, World!"); message.put("bottle", "Kickapoo Joy Juice"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -173,8 +169,7 @@ void test_ObjectMessage() { put("name", name); }}; final ObjectMessage message = new ObjectMessage(attachment); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -217,8 +212,7 @@ void test_MapMessage_serialization() { .with("key1", "val1") .with("key2", 0xDEADBEEF) .with("key3", Collections.singletonMap("key3.1", "val3.1")); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(mapMessage) .setTimeMillis(System.currentTimeMillis()) .build(); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolverTest.java index 921e15353ac..74f66e6edbe 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolverTest.java @@ -16,8 +16,11 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; +import java.util.Arrays; +import java.util.List; +import java.util.regex.PatternSyntaxException; + import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; @@ -27,10 +30,6 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.Arrays; -import java.util.List; -import java.util.regex.PatternSyntaxException; - import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; @@ -112,8 +111,7 @@ void pattern_replacement_should_work() { final StringMap contextData = new SortedArrayStringMap(); contextData.putValue("user:role", "engineer"); contextData.putValue("user:rank", "senior"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setContextData(contextData) .build(); @@ -136,8 +134,7 @@ void test_mdc_key_access() { contextData.putValue(mdcDirectlyAccessedKey, mdcDirectlyAccessedValue); final String mdcDirectlyAccessedNullPropertyKey = "mdcKey2"; contextData.putValue(mdcDirectlyAccessedNullPropertyKey, null); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .setContextData(contextData) .build(); @@ -161,8 +158,7 @@ public void test_map_key_access() { final String directlyAccessedNullPropertyKey = "mapKey2"; final Message message = new StringMapMessage() .with(directlyAccessedKey, directlyAccessedValue); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -220,8 +216,7 @@ void test_mdc_pattern() { final String mdcPatternMismatchedKey = "mdcKey2"; final String mdcPatternMismatchedValue = "mdcValue2"; contextData.putValue(mdcPatternMismatchedKey, mdcPatternMismatchedValue); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .setContextData(contextData) .build(); @@ -247,8 +242,7 @@ public void test_map_pattern() { final Message message = new StringMapMessage() .with(patternMatchedKey, patternMatchedValue) .with(patternMismatchedKey, patternMismatchedValue); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -304,8 +298,7 @@ void test_mdc_flatten() { final String mdcPatternMismatchedKey = "mdcKey2"; final String mdcPatternMismatchedValue = "mdcValue2"; contextData.putValue(mdcPatternMismatchedKey, mdcPatternMismatchedValue); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .setContextData(contextData) .build(); @@ -331,8 +324,7 @@ public void test_map_flatten() { final Message message = new StringMapMessage() .with(patternMatchedKey, patternMatchedValue) .with(patternMismatchedKey, patternMismatchedValue); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -382,8 +374,7 @@ void test_MapResolver() { // Create the log event. final StringMapMessage message = new StringMapMessage().with("key1", "val1"); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(message) .build(); @@ -436,8 +427,7 @@ void test_MapMessage_keyed_access() { final List value = Arrays.asList(1, 2); final StringMapMessage mapMessage = new StringMapMessage() .with(key, value); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setMessage(mapMessage) .setTimeMillis(System.currentTimeMillis()) .build(); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java index dad3486cb9e..1d1f039a111 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java @@ -16,14 +16,6 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; -import org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults; -import org.assertj.core.api.AbstractStringAssert; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.math.BigDecimal; @@ -37,6 +29,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; +import org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults; +import org.assertj.core.api.AbstractStringAssert; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + import static org.apache.logging.log4j.layout.template.json.TestHelpers.*; import static org.assertj.core.api.Assertions.assertThat; @@ -321,8 +320,7 @@ private static void assertSerializedException( .build(); // Create the log event. - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setThrown(exception) .build(); @@ -392,8 +390,7 @@ void JsonWriter_maxStringLength_should_work() { // Create the log event. Throwable exception = exception1(); - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setThrown(exception) .build(); @@ -537,8 +534,7 @@ void point_matchers_should_work() { .build(); // Create the log event. - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setThrown(parentError) .build(); @@ -598,8 +594,7 @@ private String matchingRegex(String string) { void nonAscii_utf8_method_name_should_get_serialized() { // Create the log event. - final LogEvent logEvent = Log4jLogEvent - .newBuilder() + final LogEvent logEvent = LogEvent.builder() .setThrown(NonAsciiUtf8MethodNameContainingException.INSTANCE) .build(); diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/RecyclerFactoriesTest.java similarity index 99% rename from log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java rename to log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/RecyclerFactoriesTest.java index 1a9d23531c0..0f4b8bdca3a 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/RecyclerFactoriesTest.java @@ -14,7 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.util; + +import java.lang.reflect.Field; +import java.util.ArrayDeque; +import java.util.concurrent.ArrayBlockingQueue; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; @@ -27,10 +31,6 @@ import org.jctools.queues.MpmcArrayQueue; import org.junit.jupiter.api.Test; -import java.lang.reflect.Field; -import java.util.ArrayDeque; -import java.util.concurrent.ArrayBlockingQueue; - class RecyclerFactoriesTest { @Test diff --git a/log4j-layout-template-json/src/main/java/module-info.java b/log4j-layout-template-json/src/main/java/module-info.java index e87682062b7..8d6fdaaada7 100644 --- a/log4j-layout-template-json/src/main/java/module-info.java +++ b/log4j-layout-template-json/src/main/java/module-info.java @@ -27,6 +27,6 @@ requires org.apache.logging.log4j; requires org.apache.logging.log4j.plugins; requires org.apache.logging.log4j.core; - requires org.jctools.core; + requires static org.jctools.core; } diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java index 4e57726fc22..d6a5118458c 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java @@ -16,6 +16,20 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.StringLayout; @@ -24,28 +38,28 @@ import org.apache.logging.log4j.core.layout.ByteBufferDestination; import org.apache.logging.log4j.core.layout.Encoder; import org.apache.logging.log4j.core.layout.TextEncoderHelper; -import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.GarbageFreeConfiguration; import org.apache.logging.log4j.core.util.StringEncoder; -import org.apache.logging.log4j.layout.template.json.resolver.*; +import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext; +import org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory; +import org.apache.logging.log4j.layout.template.json.resolver.EventResolverInterceptor; +import org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor; +import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver; +import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; -import org.apache.logging.log4j.layout.template.json.util.Recycler; -import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory; +import org.apache.logging.log4j.util.Recycler; +import org.apache.logging.log4j.util.RecyclerFactory; import org.apache.logging.log4j.layout.template.json.util.Uris; -import org.apache.logging.log4j.plugins.*; +import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Factory; +import org.apache.logging.log4j.plugins.Namespace; +import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CodingErrorAction; -import java.util.*; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - @Configurable(elementType = Layout.ELEMENT_TYPE) @Plugin public class JsonTemplateLayout implements StringLayout { @@ -110,7 +124,7 @@ private TemplateResolver createEventResolver( // Inject resolver factory and interceptor plugins. final List resolverFactories = - configuration.getComponent(new @Namespace(EventResolverFactory.CATEGORY) Key<>() {}); + configuration.getInstance(new @Namespace(EventResolverFactory.CATEGORY) Key<>() {}); final Map resolverFactoryByName = resolverFactories.stream().collect( Collectors.toMap(EventResolverFactory::getName, Function.identity(), (factory, conflictingFactory) -> { @@ -120,7 +134,7 @@ private TemplateResolver createEventResolver( throw new IllegalArgumentException(message); }, LinkedHashMap::new)); final List resolverInterceptors = - configuration.getComponent(new @Namespace(EventResolverInterceptor.CATEGORY) Key<>() {}); + configuration.getInstance(new @Namespace(EventResolverInterceptor.CATEGORY) Key<>() {}); final EventResolverStringSubstitutor substitutor = new EventResolverStringSubstitutor(configuration.getStrSubstitutor()); @@ -226,8 +240,8 @@ private StringBuilderEncoder(final Charset charset) { .newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); - this.charBuffer = CharBuffer.allocate(Constants.ENCODER_CHAR_BUFFER_SIZE); - this.byteBuffer = ByteBuffer.allocate(Constants.ENCODER_BYTE_BUFFER_SIZE); + this.charBuffer = CharBuffer.allocate(GarbageFreeConfiguration.getDefaultConfiguration().getEncoderCharBufferSize()); + this.byteBuffer = ByteBuffer.allocate(GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize()); } @Override diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java index e47acfb94a5..7f9b27df75c 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java @@ -21,10 +21,10 @@ import java.util.Locale; import java.util.TimeZone; -import org.apache.logging.log4j.layout.template.json.util.RecyclerFactories; -import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.PropertyEnvironment; +import org.apache.logging.log4j.util.RecyclerFactories; +import org.apache.logging.log4j.util.RecyclerFactory; public final class JsonTemplateLayoutDefaults { diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolver.java index 118dcfeafd5..9d82800c68f 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CaseConverterResolver.java @@ -16,13 +16,13 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; +import java.util.Locale; +import java.util.function.Function; + import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.util.JsonReader; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; - -import java.util.Locale; -import java.util.function.Function; +import org.apache.logging.log4j.util.JsonReader; /** * Converts the case of string values. diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java index aa4a1392dcb..a7b1127896e 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java @@ -18,7 +18,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; -import org.apache.logging.log4j.layout.template.json.util.Recycler; +import org.apache.logging.log4j.util.Recycler; import java.math.BigInteger; import java.util.concurrent.atomic.AtomicLong; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventAdditionalFieldInterceptor.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventAdditionalFieldInterceptor.java index a3e3395d3fb..0a9003b057b 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventAdditionalFieldInterceptor.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventAdditionalFieldInterceptor.java @@ -16,13 +16,13 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; -import org.apache.logging.log4j.core.util.JsonReader; +import java.util.Map; + import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginFactory; - -import java.util.Map; +import org.apache.logging.log4j.util.JsonReader; /** * Interceptor to add {@link EventTemplateAdditionalField diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java index d7a5793d28d..c86b2e01085 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java @@ -20,7 +20,7 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; -import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory; +import org.apache.logging.log4j.util.RecyclerFactory; import org.apache.logging.log4j.util.Strings; import java.nio.charset.Charset; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java index 9b8182ea89e..42a46e74fd4 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java @@ -18,7 +18,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; -import org.apache.logging.log4j.layout.template.json.util.Recycler; +import org.apache.logging.log4j.util.Recycler; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterConsumer; import org.apache.logging.log4j.message.ParameterVisitable; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java index 788fa5de4df..bab56552022 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java @@ -18,8 +18,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; -import org.apache.logging.log4j.layout.template.json.util.Recycler; -import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory; +import org.apache.logging.log4j.util.Recycler; +import org.apache.logging.log4j.util.RecyclerFactory; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.TriConsumer; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java index 92c2d33252c..7566939e0b4 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java @@ -17,6 +17,8 @@ package org.apache.logging.log4j.layout.template.json.resolver; import org.apache.logging.log4j.layout.template.json.util.*; +import org.apache.logging.log4j.util.Recycler; +import org.apache.logging.log4j.util.RecyclerFactory; import java.util.List; import java.util.function.Supplier; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java index adc40c09ac4..e05484b8599 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; -import org.apache.logging.log4j.core.util.JsonReader; -import org.apache.logging.log4j.layout.template.json.util.JsonWriter; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -26,6 +23,9 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.apache.logging.log4j.layout.template.json.util.JsonWriter; +import org.apache.logging.log4j.util.JsonReader; + /** * Main class for compiling {@link TemplateResolver}s from a template. */ diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java deleted file mode 100644 index 99787553373..00000000000 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.layout.template.json.util; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class ThreadLocalRecycler implements Recycler { - - private final Consumer cleaner; - - private final ThreadLocal holder; - - public ThreadLocalRecycler( - final Supplier supplier, - final Consumer cleaner) { - this.cleaner = cleaner; - this.holder = ThreadLocal.withInitial(supplier); - } - - @Override - public V acquire() { - final V value = holder.get(); - cleaner.accept(value); - return value; - } - - @Override - public void release(final V value) {} - -} diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java index c9715706462..ae6b1809227 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.layout.template.json; -import org.apache.logging.log4j.core.util.JsonReader; -import org.apache.logging.log4j.util.Strings; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -40,6 +37,9 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.apache.logging.log4j.util.JsonReader; +import org.apache.logging.log4j.util.Strings; + /** * Utility class to summarize {@link JsonTemplateLayoutBenchmark} results in Asciidoctor. *

    diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java index 8edeac77044..71c2346bc79 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.layout.template.json; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; + import co.elastic.logging.log4j2.EcsLayout; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -27,14 +31,10 @@ import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.jackson.json.layout.JsonLayout; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField; -import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecyclerFactory; +import org.apache.logging.log4j.util.RecyclerFactories; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.List; - @State(Scope.Thread) public class JsonTemplateLayoutBenchmarkState { @@ -85,7 +85,7 @@ private static JsonTemplateLayout createJtl4JsonLayout() { .setConfiguration(CONFIGURATION) .setCharset(CHARSET) .setEventTemplateUri("classpath:JsonLayout.json") - .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance()) + .setRecyclerFactory(RecyclerFactories.ofSpec(null)) .build(); } @@ -103,7 +103,7 @@ private static JsonTemplateLayout createJtl4EcsLayout() { .setConfiguration(CONFIGURATION) .setCharset(CHARSET) .setEventTemplateUri("classpath:EcsLayout.json") - .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance()) + .setRecyclerFactory(RecyclerFactories.ofSpec(null)) .setEventTemplateAdditionalFields(additionalFields) .build(); } @@ -114,7 +114,7 @@ private static JsonTemplateLayout createJtl4GelfLayout() { .setConfiguration(CONFIGURATION) .setCharset(CHARSET) .setEventTemplateUri("classpath:GelfLayout.json") - .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance()) + .setRecyclerFactory(RecyclerFactories.ofSpec(null)) .setEventTemplateAdditionalFields( new EventTemplateAdditionalField[]{ // Adding "host" as a constant rather than using diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java index 959f6b2bb69..f61fbafd044 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java @@ -19,13 +19,13 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.StringLayout; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.AbstractStringLayout; import org.apache.logging.log4j.core.layout.ByteBufferDestination; import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper; @@ -76,15 +76,15 @@ public void setUp() { bytes[i] = (byte)i; } - usAsciiGetBytesLayout = new GetBytesLayout(Charset.forName("US-ASCII")); - iso8859_1GetBytesLayout = new GetBytesLayout(Charset.forName("ISO-8859-1")); - utf8GetBytesLayout = new GetBytesLayout(Charset.forName("UTF-8")); - utf16GetBytesLayout = new GetBytesLayout(Charset.forName("UTF-16")); + usAsciiGetBytesLayout = new GetBytesLayout(StandardCharsets.US_ASCII); + iso8859_1GetBytesLayout = new GetBytesLayout(StandardCharsets.ISO_8859_1); + utf8GetBytesLayout = new GetBytesLayout(StandardCharsets.UTF_8); + utf16GetBytesLayout = new GetBytesLayout(StandardCharsets.UTF_16); - usAsciiEncodeLayout = new EncodeLayout(Charset.forName("US-ASCII")); - iso8859_1EncodeLayout = new EncodeLayout(Charset.forName("ISO-8859-1")); - utf8EncodeLayout = new EncodeLayout(Charset.forName("UTF-8")); - utf16EncodeLayout = new EncodeLayout(Charset.forName("UTF-16")); + usAsciiEncodeLayout = new EncodeLayout(StandardCharsets.US_ASCII); + iso8859_1EncodeLayout = new EncodeLayout(StandardCharsets.ISO_8859_1); + utf8EncodeLayout = new EncodeLayout(StandardCharsets.UTF_8); + utf16EncodeLayout = new EncodeLayout(StandardCharsets.UTF_16); final StringBuilder msg = new StringBuilder(); msg.append(MESSAGE); @@ -105,7 +105,7 @@ private static LogEvent createLogEvent(final Message message) { final StackTraceElement location = null; final long timestamp = 12345678; - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // @@ -117,7 +117,7 @@ private static LogEvent createLogEvent(final Message message) { .setThreadName(threadName) // .setSource(location) // .setTimeMillis(timestamp) // - .build(); + .get(); } @BenchmarkMode(Mode.Throughput) diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ConcurrentAsyncLoggerToFileBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ConcurrentAsyncLoggerToFileBenchmark.java index fcdee8672d1..23c037cb6c1 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ConcurrentAsyncLoggerToFileBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ConcurrentAsyncLoggerToFileBenchmark.java @@ -86,7 +86,7 @@ public static class BenchmarkState { @Setup public final void before() throws IOException { Files.deleteIfExists(Path.of("target", "ConcurrentAsyncLoggerToFileBenchmark.log")); - System.setProperty(LoggingSystemProperties.SYSTEM_IS_WEBAPP, "false"); + System.setProperty(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP, "false"); asyncLoggerType.setProperties(); queueFullPolicy.setProperties(); logger = LogManager.getLogger(ConcurrentAsyncLoggerToFileBenchmark.class); diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/FileAppenderThrowableBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/FileAppenderThrowableBenchmark.java index c61fcfd9fb1..b1e25d1170f 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/FileAppenderThrowableBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/FileAppenderThrowableBenchmark.java @@ -17,9 +17,7 @@ package org.apache.logging.log4j.perf.jmh; import java.io.File; -import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.TimeUnit; import java.util.logging.FileHandler; @@ -29,6 +27,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.async.AsyncLoggerContext; import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector; +import org.apache.logging.log4j.core.impl.Log4jProperties; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.openjdk.jmh.annotations.Benchmark; @@ -60,10 +59,10 @@ public class FileAppenderThrowableBenchmark { static { // log4j2 - System.setProperty(LoggingSystemProperties.SYSTEM_IS_WEBAPP, "false"); - System.setProperty("log4j.configurationFile", "log4j2-perf-file-throwable.xml"); + System.setProperty(LoggingSystemProperties.SYSTEM_ENABLE_WEBAPP, "false"); + System.setProperty(Log4jProperties.CONFIG_LOCATION, "log4j2-perf-file-throwable.xml"); // log4j 1.2 - System.setProperty("log4j.configuration", "log4j12-perf-file-throwable.xml"); + System.setProperty(Log4jProperties.CONFIG_V1_LOCATION, "log4j12-perf-file-throwable.xml"); // logback System.setProperty("logback.configurationFile", "logback-perf-file-throwable.xml"); } diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java index dd64055fcf2..d699bf57c52 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java @@ -24,7 +24,6 @@ import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.NullConfiguration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.GelfLayout; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.Message; @@ -64,7 +63,7 @@ private static LogEvent createLogEvent() { final StackTraceElement location = null; final long timestamp = 12345678; - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // @@ -76,7 +75,7 @@ private static LogEvent createLogEvent() { .setThreadName(threadName) // .setSource(location) // .setTimeMillis(timestamp) // - .build(); + .get(); } Appender appender; diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4jLogEventBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ImmutableLogEventBenchmark.java similarity index 63% rename from log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4jLogEventBenchmark.java rename to log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ImmutableLogEventBenchmark.java index 6d2eb213bb5..1d2260cce17 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4jLogEventBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ImmutableLogEventBenchmark.java @@ -18,7 +18,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.internal.FixedPreciseClock; import org.apache.logging.log4j.message.Message; @@ -29,10 +28,8 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; -import java.io.Serializable; - @State(Scope.Thread) -public class Log4jLogEventBenchmark { +public class ImmutableLogEventBenchmark { private static Message MESSAGE; private static Throwable ERROR; private static TestClass TESTER; @@ -52,25 +49,25 @@ public void testBaseline(final Blackhole bh) { @Benchmark public LogEvent createLogEventWithoutExceptionUsingBuilder() { - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setLoggerName("a.b.c") .setLoggerFqcn("a.b.c") .setLevel(Level.INFO) .setMessage(MESSAGE) .setClock(CLOCK) - .build(); + .toImmutable(); } @Benchmark public LogEvent createLogEventWithExceptionUsingBuilder() { - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setLoggerName("a.b.c") .setLoggerFqcn("a.b.c") .setLevel(Level.INFO) .setMessage(MESSAGE) .setThrown(ERROR) .setClock(CLOCK) - .build(); + .toImmutable(); } @Benchmark @@ -79,61 +76,18 @@ public StackTraceElement getSourceLocationOfLogEvent() { return TESTER.getEventSource(this.getClass().getName()); } - @Benchmark - public Serializable createSerializableLogEventProxyWithoutException(final Blackhole bh) { - final Log4jLogEvent event = Log4jLogEvent.newBuilder() - .setLoggerName("a.b.c") - .setLoggerFqcn("a.b.c") - .setLevel(Level.INFO) - .setMessage(MESSAGE) - .setClock(CLOCK) - .build(); - final Serializable obj = Log4jLogEvent.serialize(event, false); - bh.consume(obj); - return obj; - } - - @Benchmark - public Serializable createSerializableLogEventProxyWithoutExceptionWithLocation(final Blackhole bh) { - final Log4jLogEvent event = Log4jLogEvent.newBuilder() - .setLoggerName("a.b.c") - .setLoggerFqcn("a.b.c") - .setLevel(Level.INFO) - .setMessage(MESSAGE) - .setClock(CLOCK) - .build(); - final Serializable obj = Log4jLogEvent.serialize(event, true); - bh.consume(obj); - return obj; - } - - @Benchmark - public Serializable createSerializableLogEventProxyWithException(final Blackhole bh) { - final Log4jLogEvent event = Log4jLogEvent.newBuilder() - .setLoggerName("a.b.c") - .setLoggerFqcn("a.b.c") - .setLevel(Level.INFO) - .setMessage(MESSAGE) - .setThrown(ERROR) - .setClock(CLOCK) - .build(); - final Serializable obj = Log4jLogEvent.serialize(event, false); - bh.consume(obj); - return obj; - } - private static class TestClass { private static final String FQCN = TestClass.class.getName(); public StackTraceElement getEventSource(final String loggerName) { - final LogEvent event = Log4jLogEvent.newBuilder() + final LogEvent event = LogEvent.builder() .setLoggerName(loggerName) .setLoggerFqcn(FQCN) .setLevel(Level.INFO) .setMessage(MESSAGE) .setClock(CLOCK) - .build(); - event.setIncludeLocation(true); + .includeLocation(true) + .toImmutable(); return event.getSource(); } } diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java index a6c60ec1d2a..1c120766302 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java @@ -27,7 +27,6 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.StringMap; @@ -80,7 +79,7 @@ private static LogEvent createLogEvent() { final StackTraceElement location = null; final long timestamp = System.currentTimeMillis(); - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggerConfigBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggerConfigBenchmark.java index 976b842bf77..b7087a854ff 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggerConfigBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggerConfigBenchmark.java @@ -16,6 +16,13 @@ */ package org.apache.logging.log4j.perf.jmh; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; @@ -23,7 +30,6 @@ import org.apache.logging.log4j.core.config.AppenderControl; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.SimpleMessage; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Scope; @@ -31,13 +37,6 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - // ============================== HOW TO RUN THIS TEST: ==================================== // // In sampling mode (latency test): @@ -95,7 +94,7 @@ public void testBaseline(final Blackhole bh) { } private static LogEvent createLogEventWithoutException() { - return Log4jLogEvent.newBuilder() + return LogEvent.builder() .setLoggerName("a.b.c") .setLoggerFqcn("a.b.c") .setLevel(Level.INFO) diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java index bff60219569..cf9bcfac5a6 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java @@ -24,7 +24,6 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; @@ -217,7 +216,7 @@ private static LogEvent createLogEvent() { final StackTraceElement location = null; final long timestamp = 12345678; - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java index 417930e38d4..d7cca606b0b 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java @@ -21,11 +21,15 @@ import java.io.IOException; import java.nio.charset.Charset; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.encoder.PatternLayoutEncoder; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggingEvent; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; @@ -35,12 +39,6 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.encoder.PatternLayoutEncoder; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.classic.spi.LoggingEvent; - /** * Compares Log4j2 with Logback PatternLayout performance. */ @@ -84,7 +82,7 @@ private static LogEvent createLog4j2Event() { final StackTraceElement location = null; final long timestamp = 12345678; - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java index de7250cd9f0..36e2b5b471e 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java @@ -25,7 +25,6 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.ByteBufferDestination; import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper; import org.apache.logging.log4j.core.layout.PatternLayout; @@ -117,7 +116,7 @@ private static LogEvent createLogEvent() { final StackTraceElement location = null; final long timestamp = 12345678; - return Log4jLogEvent.newBuilder() // + return LogEvent.builder() // .setLoggerName("name(ignored)") // .setMarker(marker) // .setLoggerFqcn(fqcn) // diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java index 94659687df2..861a1ce5c40 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java @@ -25,14 +25,13 @@ import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.ThreadContextBenchmarkAccess; import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; import org.apache.logging.log4j.perf.nogc.OpenHashStringMap; import org.apache.logging.log4j.spi.CopyOnWriteOpenHashMapThreadContextMap; import org.apache.logging.log4j.spi.DefaultThreadContextMap; import org.apache.logging.log4j.spi.GarbageFreeOpenHashMapThreadContextMap; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.spi.LoggingSystemProperties; import org.apache.logging.log4j.spi.ThreadContextMap; import org.apache.logging.log4j.util.SortedArrayStringMap; @@ -104,9 +103,9 @@ public class ThreadContextBenchmark { @Setup public void setup() { System.setProperty(LoggingSystemProperties.THREAD_CONTEXT_MAP_CLASS, IMPLEMENTATIONS.get(threadContextMapAlias).getName()); - ThreadContextBenchmarkAccess.init(); + ThreadContext.init(); - injector = ContextDataInjectorFactory.createInjector(); + injector = LoggingSystem.getInstance().getInstanceFactory().getInstance(ContextDataInjector.class); System.out.println(threadContextMapAlias + ": Injector = " + injector); reusableContextData = threadContextMapAlias.contains("Array") @@ -140,7 +139,7 @@ public void setup() { @TearDown public void tearDown() { System.clearProperty(LoggingSystemProperties.THREAD_CONTEXT_MAP_CLASS); - ThreadContextBenchmarkAccess.init(); + ThreadContext.init(); } public void clearAndPut() { diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadLocalVsPoolBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadLocalVsPoolBenchmark.java index 2996dec52f8..c28f54f954e 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadLocalVsPoolBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadLocalVsPoolBenchmark.java @@ -17,11 +17,12 @@ package org.apache.logging.log4j.perf.jmh; +import java.util.List; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternFormatter; import org.apache.logging.log4j.core.pattern.PatternParser; @@ -32,8 +33,6 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import java.util.List; - /** * Checks {@link PatternFormatter} performance with various StringBuilder * caching strategies: no-op, ThreadLocal, and JCTools MPMC queue. @@ -64,8 +63,7 @@ private static LogEvent createLogEvent() { final String messageString = "AB!(%087936DZYXQWEIOP$#^~-=/> layout) { @Override public void append(final LogEvent event) { - if (Constants.ENABLE_DIRECT_ENCODERS) { + if (GarbageFreeConfiguration.getDefaultConfiguration().isDirectEncodersEnabled()) { getLayout().encode(event, this); drain(byteBuffer); } else { diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPropertyConditionTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPropertyConditionTest.java index d6e50b0478f..894c98fdf4a 100644 --- a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPropertyConditionTest.java +++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPropertyConditionTest.java @@ -19,7 +19,6 @@ import org.apache.logging.log4j.plugins.Factory; import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.di.DI; -import org.apache.logging.log4j.util.PropertiesUtil; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.ClearSystemProperty; @@ -31,13 +30,13 @@ class OnPropertyConditionTest { static class OnProperty { - @ConditionalOnProperty(name = "foo.bar", value = "true") + @ConditionalOnProperty(name = "log4j2.*.foo.bar", value = "true") @Factory String truth() { return "truth"; } - @ConditionalOnProperty(name = "foo.bar") + @ConditionalOnProperty(name = "log4j2.*.foo.bar") @Ordered(Ordered.LAST) @Factory String string() { @@ -52,25 +51,22 @@ String backup() { } @Test - @ClearSystemProperty(key = "foo.bar") + @ClearSystemProperty(key = "log4j2.*.foo.bar") void whenPropertyAbsent() { - ((PropertiesUtil) PropertiesUtil.getProperties()).reload(); final String value = DI.createInjector(OnProperty.class).getInstance(String.class); assertEquals("goodbye", value); } @Test - @SetSystemProperty(key = "foo.bar", value = "whatever") + @SetSystemProperty(key = "log4j2.*.foo.bar", value = "whatever") void whenPropertyPresent() { - ((PropertiesUtil) PropertiesUtil.getProperties()).reload(); final String value = DI.createInjector(OnProperty.class).getInstance(String.class); assertEquals("hello", value); } @Test - @SetSystemProperty(key = "foo.bar", value = "true") + @SetSystemProperty(key = "log4j2.*.foo.bar", value = "true") void whenPropertyMatches() { - ((PropertiesUtil) PropertiesUtil.getProperties()).reload(); final String value = DI.createInjector(OnProperty.class).getInstance(String.class); assertEquals("truth", value); } diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java index 5166d69346b..c146b9bf5ac 100644 --- a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java +++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java @@ -423,15 +423,6 @@ void supplierAliases() { .allMatch("bar"::equals); } - static class CustomSingletonScope implements Scope { - private final Map, Object> bindings = new ConcurrentHashMap<>(); - - @Override - public Supplier get(final Key key, final Supplier unscoped) { - return () -> Cast.cast(bindings.computeIfAbsent(key, ignored -> unscoped.get())); - } - } - @Retention(RetentionPolicy.RUNTIME) @ScopeType @interface CustomSingleton { @@ -444,9 +435,67 @@ static class CustomInstance { @Test void registerCustomScope() { final Injector injector = DI.createInjector(); - injector.registerScope(CustomSingleton.class, new CustomSingletonScope()); + injector.registerScope(CustomSingleton.class, new SimpleScope("Custom")); final var factory = injector.getFactory(CustomInstance.class); - assertThat(factory.get()).isSameAs(factory.get()).isSameAs(injector.getInstance(CustomInstance.class)); + assertThat(factory.get()) + .isSameAs(factory.get()) + .isSameAs(injector.getInstance(CustomInstance.class)); + } + + @Test + void deferredScopeRegistration() { + final Injector injector = DI.createInjector(); + final Supplier factory = injector.getFactory(CustomInstance.class); + injector.registerScope(CustomSingleton.class, new SimpleScope("Custom")); + assertThat(factory.get()) + .isSameAs(factory.get()) + .isSameAs(injector.getInstance(CustomInstance.class)); + } + + static class UnscopedBean { + } + + static class ScopedBundle { + @Factory + @CustomSingleton + UnscopedBean scopedBean() { + return new UnscopedBean(); + } + } + + @Test + void deferredScopeRegistrationBundle() { + final Injector injector = DI.createInjector(ScopedBundle.class); + final Supplier factory = injector.getFactory(UnscopedBean.class); + injector.registerScope(CustomSingleton.class, new SimpleScope("Custom")); + assertThat(factory.get()) + .isSameAs(factory.get()) + .isSameAs(injector.getInstance(UnscopedBean.class)); + } + + interface Api { + } + + @Singleton + static class Impl implements Api { + } + + static class CustomScopeBundle { + @Factory + @CustomSingleton + Api api() { + return new Impl(); + } + } + + @Test + void deferredScopeRegistrationInterfaceBundle() { + final Injector injector = DI.createInjector(CustomScopeBundle.class); + final Supplier factory = injector.getFactory(Api.class); + injector.registerScope(CustomSingleton.class, new SimpleScope("Custom")); + assertThat(factory.get()) + .isSameAs(factory.get()) + .isSameAs(injector.getInstance(Api.class)); } static class ClassBundle { diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ConfigurationScoped.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ConfigurationScoped.java new file mode 100644 index 00000000000..29f84ccfddb --- /dev/null +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ConfigurationScoped.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.plugins; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Scope type where provided instances are singletons within a particular {@code Configuration}. Fresh instances + * are provided for each lifecycle of a configuration. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@Inherited +@ScopeType +public @interface ConfigurationScoped { +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ContextScoped.java similarity index 57% rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ContextScoped.java index ce0dc999bfc..7c3fbad4ad2 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/ContextScoped.java @@ -14,22 +14,24 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.layout.template.json.util; +package org.apache.logging.log4j.plugins; -import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.convert.TypeConverter; -import org.apache.logging.log4j.plugins.convert.TypeConverters; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.logging.log4j.spi.LoggerContext; /** - * The default string (i.e., recycler factory spec) to {@link RecyclerFactory} type converter. + * Scope type where provided instances are singletons within a particular {@link LoggerContext}. */ -@TypeConverters -@Plugin -public final class RecyclerFactoryConverter implements TypeConverter { - - @Override - public RecyclerFactory convert(final String recyclerFactorySpec) { - return RecyclerFactories.ofSpec(recyclerFactorySpec); - } - +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@Inherited +@ScopeType +public @interface ContextScoped { } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPropertyCondition.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPropertyCondition.java index bb1e093689c..9415a8e63d0 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPropertyCondition.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPropertyCondition.java @@ -22,8 +22,8 @@ import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.plugins.util.AnnotationUtil; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; @Singleton public class OnPropertyCondition implements Condition { @@ -38,9 +38,11 @@ public boolean matches(final Key key, final AnnotatedElement element) { } final String name = annotation.name(); final String value = annotation.value(); - final String property = PropertiesUtil.getProperties().getStringProperty(name); - final boolean result = property != null && (value.isEmpty() || value.equalsIgnoreCase(property)); - LOGGER.debug("ConditionalOnProperty {} for name='{}', value='{}'; property='{}'", result, name, value, property); + final boolean result = LoggingSystem.getPropertyResolver() + .getString(name) + .filter(property -> value.isEmpty() || value.equalsIgnoreCase(property)) + .isPresent(); + LOGGER.debug("ConditionalOnProperty {} for name='{}', value='{}'", result, name, value); return result; } } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java index 0cde8a2e796..8bd0e65c70c 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java @@ -64,10 +64,16 @@ import org.apache.logging.log4j.plugins.validation.ConstraintValidationException; import org.apache.logging.log4j.plugins.validation.ConstraintValidator; import org.apache.logging.log4j.plugins.visit.NodeVisitor; +import org.apache.logging.log4j.spi.ClassFactory; +import org.apache.logging.log4j.spi.InstanceFactory; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Cast; import org.apache.logging.log4j.util.EnglishEnums; import org.apache.logging.log4j.util.Lazy; +import org.apache.logging.log4j.util.PropertyResolver; +import org.apache.logging.log4j.util.RecyclerFactories; +import org.apache.logging.log4j.util.RecyclerFactory; import org.apache.logging.log4j.util.ServiceRegistry; import org.apache.logging.log4j.util.StringBuilders; @@ -84,11 +90,14 @@ class DefaultInjector implements Injector { DefaultInjector() { bindingMap = new BindingMap(); bindingMap.put(KEY, () -> this); - scopes.put(Singleton.class, new SingletonScope()); + bindingMap.put(Key.forClass(InstanceFactory.class), () -> this); + scopes.put(Singleton.class, new SimpleScope("SingletonScoped")); } DefaultInjector(final DefaultInjector original) { bindingMap = new BindingMap(original.bindingMap); + bindingMap.put(KEY, () -> this); + bindingMap.put(Key.forClass(InstanceFactory.class), () -> this); scopes.putAll(original.scopes); typeConverters.putAll(original.typeConverters); accessor = original.accessor; @@ -96,6 +105,11 @@ class DefaultInjector implements Injector { @Override public void init() { + // bridge into LoggingSystem and set up early bindings before invoking callback services + final LoggingSystem system = LoggingSystem.getInstance(); + system.setInstanceFactory(this); + bindingMap.put(Key.forClass(PropertyResolver.class), system::propertyResolver); + bindingMap.put(Key.forClass(ClassFactory.class), system::getClassFactory); final List callbacks = ServiceRegistry.getInstance() .getServices(InjectorCallback.class, MethodHandles.lookup(), null); callbacks.sort(InjectorCallback.COMPARATOR); @@ -118,6 +132,11 @@ public Supplier getFactory(final Key key) { return getFactory(key, Set.of(), null, Set.of()); } + @Override + public Optional tryGetInstance(final Class type) { + return getOptionalInstance(Key.forClass(type), Set.of(), null, Set.of()); + } + @Override public TypeConverter getTypeConverter(final Type type) { if (typeConverters.isEmpty()) { @@ -249,7 +268,6 @@ private Supplier getFactory( } final Class rawType = key.getRawType(); - final Scope scope = getScopeForType(rawType); // @Namespace PluginNamespace injection if (rawType == PluginNamespace.class && !key.getNamespace().isEmpty()) { @@ -301,7 +319,7 @@ private Supplier getFactory( injectMembers(key, node, instance, chain, debugLog); return instance; }; - return bindingMap.merge(key, scope.get(key, instanceSupplier)); + return bindingMap.merge(key, getScoped(getScopeType(rawType), key, instanceSupplier)); } private Supplier createPluginNamespaceFactory(final Key key) { @@ -317,7 +335,7 @@ private Stream> streamPluginsFromNamespace(final Key itemKe return namespace.stream() .filter(pluginType -> TypeUtil.isAssignable(type, pluginType.getPluginClass())) .sorted(Comparator.comparing(PluginType::getPluginClass, OrderedComparator.INSTANCE)) - .map(o -> Cast.cast(o)); + .map(Cast::cast); } private Stream streamPluginInstancesFromNamespace(final Key key) { @@ -425,6 +443,7 @@ private void initializeTypeConverters() { registerTypeConverter(Short.class, Short::valueOf); registerTypeAlias(Short.class, Short.TYPE); registerTypeConverter(String.class, s -> s); + registerTypeConverter(RecyclerFactory.class, RecyclerFactories::ofSpec); } private TypeConverter registerTypeConverter(final Type type, final TypeConverter converter) { @@ -432,12 +451,10 @@ private TypeConverter registerTypeConverter(final Type type, final TypeConver if (conflictingConverter != null) { final boolean overridable; if (converter instanceof Comparable) { - @SuppressWarnings("unchecked") final Comparable> comparableConverter = - (Comparable>) converter; + final Comparable> comparableConverter = Cast.cast(converter); overridable = comparableConverter.compareTo(conflictingConverter) < 0; } else if (conflictingConverter instanceof Comparable) { - @SuppressWarnings("unchecked") final Comparable> comparableConflictingConverter = - (Comparable>) conflictingConverter; + final Comparable> comparableConflictingConverter = Cast.cast(conflictingConverter); overridable = comparableConflictingConverter.compareTo(converter) > 0; } else { overridable = false; @@ -625,7 +642,7 @@ private List> createMethodBindings(final Object instance, final M .toArray(); return Cast.cast(accessor.invokeMethod(method, instance, args)); }; - final Supplier factory = getScopeForMethod(method).get(primaryKey, unscoped); + final Supplier factory = getScoped(getScopeType(method), primaryKey, unscoped); final Collection aliases = Keys.getAliases(method); final List> bindings = new ArrayList<>(1 + aliases.size()); bindings.add(Binding.bind(primaryKey, factory)); @@ -676,14 +693,21 @@ private Map> getArgumentFactories( return argFactories; } - private Scope getScopeForMethod(final Method method) { + private Class getScopeType(final Method method) { final Annotation methodScope = AnnotationUtil.getMetaAnnotation(method, ScopeType.class); - return methodScope != null ? getScope(methodScope.annotationType()) : getScopeForType(method.getReturnType()); + return methodScope != null ? methodScope.annotationType() : getScopeType(method.getReturnType()); } - private Scope getScopeForType(final Class type) { + private Class getScopeType(final Class type) { final Annotation scope = AnnotationUtil.getMetaAnnotation(type, ScopeType.class); - return scope != null ? getScope(scope.annotationType()) : DefaultScope.INSTANCE; + return scope != null ? scope.annotationType() : null; + } + + private Supplier getScoped(final Class scopeType, final Key key, final Supplier unscoped) { + return () -> { + final Scope scope = scopeType != null ? scopes.getOrDefault(scopeType, DefaultScope.INSTANCE) : DefaultScope.INSTANCE; + return scope.get(key, unscoped).get(); + }; } private static boolean isCompatibleValidator( @@ -819,20 +843,6 @@ private static boolean isInjectable(final Method method) { parameter -> AnnotationUtil.isMetaAnnotationPresent(parameter, QualifierType.class)); } - private static class SingletonScope implements Scope { - private final Map, Supplier> singletonProviders = new ConcurrentHashMap<>(); - - @Override - public Supplier get(final Key key, final Supplier unscoped) { - return Cast.cast(singletonProviders.computeIfAbsent(key, ignored -> Lazy.lazy(unscoped)::value)); - } - - @Override - public String toString() { - return "[SingletonScope; size=" + singletonProviders.size() + "]"; - } - } - private enum DefaultScope implements Scope { INSTANCE; diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java index c9b01a5aa27..974b2d0906b 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java @@ -14,17 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ - package org.apache.logging.log4j.plugins.di; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.function.Supplier; + import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.FactoryType; import org.apache.logging.log4j.plugins.Node; import org.apache.logging.log4j.plugins.convert.TypeConverter; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.function.Supplier; +import org.apache.logging.log4j.spi.InstanceFactory; /** * Manages dependency injection of a set of bindings between {@link Key}s and {@link Supplier}s lifecycle-bound to @@ -46,7 +46,7 @@ * plugin class to return the plugin instance. Configuring a node configures its children nodes and consumes its * attributes before returning the plugin instance.

    */ -public interface Injector { +public interface Injector extends InstanceFactory { /** * The key corresponding to the current Injector. */ @@ -105,6 +105,7 @@ default T getInstance(final Key key) { * @param type of instance * @return an instance of the provided class */ + @Override default T getInstance(final Class clazz) { return getFactory(clazz).get(); } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java index e62d0f1c5ff..16290791f92 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java @@ -36,8 +36,11 @@ import org.apache.logging.log4j.util.Strings; /** - * Type with an optional {@link QualifierType} type, name, and namespace. Keys are used for binding to and looking up instance - * factories via {@link Injector}. + * Provides a type token for generic types with associated dependency injection metadata. Keys contain optional + * metadata including a {@linkplain org.apache.logging.log4j.plugins.Namespace namespace}, a + * {@linkplain org.apache.logging.log4j.plugins.Named name}, a {@linkplain QualifierType qualifier annotation}, + * and an {@linkplain Ordered ordinal value}. Keys are used for binding and looking up instance factories (sometimes + * referred to as beans or bindings) via the {@link Injector} API. * * @param type of key */ @@ -192,8 +195,20 @@ public final int hashCode() { public final String toString() { String string = toString; if (string == null) { - toString = string = String.format("Key{namespace='%s', name='%s', type=%s, qualifierType=%s}", - namespace, name, type.getTypeName(), qualifierType != null ? qualifierType.getSimpleName() : Strings.EMPTY); + final StringBuilder sb = new StringBuilder(); + if (Strings.isNotEmpty(namespace)) { + sb.append("@Namespace(\"").append(namespace).append("\") "); + } + if (Strings.isNotEmpty(name)) { + sb.append("@Named(\"").append(name).append("\") "); + } + if (qualifierType != null) { + sb.append('@').append(qualifierType.getSimpleName()).append(' '); + } + if (order != 0) { + sb.append("@Ordered(").append(order).append(") "); + } + toString = string = sb.append(type.getTypeName()).toString(); } return string; } @@ -202,6 +217,7 @@ public final String toString() { * Creates a Key for the class. */ public static Key forClass(final Class clazz) { + // TODO: this should be able to reuse cached instances return builder() .setType(clazz) .setQualifierType(getQualifierType(clazz)) diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Keys.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Keys.java index 4ab14d0e83d..1ca951065d7 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Keys.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Keys.java @@ -27,6 +27,7 @@ import java.util.Optional; import java.util.function.Function; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.plugins.Named; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.internal.util.BeanUtils; @@ -44,6 +45,8 @@ private Keys() { throw new IllegalStateException("Utility class"); } + public static final Key DEFAULT_STATUS_LEVEL_KEY = new @Named("StatusLogger") Key<>() {}; + public static final String SUBSTITUTOR_NAME = "StringSubstitutor"; public static final Key> SUBSTITUTOR_KEY = new @Named(SUBSTITUTOR_NAME) Key<>() {}; @@ -143,7 +146,11 @@ public static String getName(final Class type) { } private static Optional getSpecifiedName(final AnnotatedElement element) { - for (final Annotation annotation : element.getAnnotations()) { + return getSpecifiedName(List.of(element.getAnnotations())); + } + + public static Optional getSpecifiedName(final Collection annotations) { + for (final Annotation annotation : annotations) { final Optional name = getSpecifiedNameForAnnotation(annotation); if (name.isPresent()) { return name; @@ -170,8 +177,8 @@ public static Collection getAliases(final AnnotatedElement element) { } private static Collection getAliasesForAnnotation(final A annotation) { - @SuppressWarnings("unchecked") final var providerType = (Class>) - annotation.annotationType().getAnnotation(AliasesProvider.class).value(); + final Class> providerType = + Cast.cast(annotation.annotationType().getAnnotation(AliasesProvider.class).value()); final AnnotatedElementAliasesProvider provider = ReflectionUtil.instantiate(providerType); return provider.getAliases(annotation); } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/SimpleScope.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/SimpleScope.java new file mode 100644 index 00000000000..c5fba405688 --- /dev/null +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/SimpleScope.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.plugins.di; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import org.apache.logging.log4j.util.Cast; +import org.apache.logging.log4j.util.Lazy; + +/** + * Simple Scope where instances are lazily initialized at most once per key. + */ +public class SimpleScope implements Scope { + private final Map, Supplier> scopedFactories = new ConcurrentHashMap<>(); + private final Supplier nameSupplier; + + public SimpleScope(final Supplier nameSupplier) { + this.nameSupplier = nameSupplier; + } + + public SimpleScope(final String name) { + this.nameSupplier = () -> name; + } + + @Override + public Supplier get(final Key key, final Supplier unscoped) { + return Cast.cast(scopedFactories.computeIfAbsent(key, ignored -> Lazy.lazy(unscoped)::value)); + } + + @Override + public String toString() { + return '[' + nameSupplier.get() + "; size=" + scopedFactories.size() + ']'; + } +} diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredPropertyValidator.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredPropertyValidator.java index 1bc954f0343..bee1d271205 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredPropertyValidator.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredPropertyValidator.java @@ -19,8 +19,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.plugins.validation.ConstraintValidator; import org.apache.logging.log4j.plugins.validation.constraints.RequiredProperty; +import org.apache.logging.log4j.spi.LoggingSystem; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; /** * Validator that checks that a property exists and has the correct value if a value is required. @@ -40,7 +40,9 @@ public void initialize(final RequiredProperty anAnnotation) { @Override public boolean isValid(final String name, final Object value) { - String property = PropertiesUtil.getProperties().getStringProperty(annotation.name()); + final String property = LoggingSystem.getPropertyResolver() + .getString(annotation.name()) + .orElse(null); if (property == null) { LOGGER.error("{} cannot be used. Required property {} is not defined", name, annotation.name()); return false; diff --git a/log4j-samples/log4j-samples-configuration/src/main/java/org/apache/logging/log4j/configuration/CustomConfiguration.java b/log4j-samples/log4j-samples-configuration/src/main/java/org/apache/logging/log4j/configuration/CustomConfiguration.java index 1e80d77ce5d..9cc0f6cc772 100644 --- a/log4j-samples/log4j-samples-configuration/src/main/java/org/apache/logging/log4j/configuration/CustomConfiguration.java +++ b/log4j-samples/log4j-samples-configuration/src/main/java/org/apache/logging/log4j/configuration/CustomConfiguration.java @@ -16,8 +16,6 @@ */ package org.apache.logging.log4j.configuration; -import java.io.Serializable; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Layout; @@ -62,7 +60,7 @@ public CustomConfiguration(final LoggerContext loggerContext, final Configuratio super(loggerContext, source); setName(CONFIG_NAME); - final Layout layout = PatternLayout.newBuilder() + final Layout layout = PatternLayout.newBuilder() .setPattern(DEFAULT_PATTERN) .setConfiguration(this) .build(); diff --git a/log4j-samples/log4j-samples-loggerProperties/src/test/java/org/apache/logging/log4j/MapMessageLookupTest.java b/log4j-samples/log4j-samples-loggerProperties/src/test/java/org/apache/logging/log4j/MapMessageLookupTest.java index d2f55ccb4eb..7d43c54be2d 100644 --- a/log4j-samples/log4j-samples-loggerProperties/src/test/java/org/apache/logging/log4j/MapMessageLookupTest.java +++ b/log4j-samples/log4j-samples-loggerProperties/src/test/java/org/apache/logging/log4j/MapMessageLookupTest.java @@ -17,18 +17,17 @@ package org.apache.logging.log4j; -import static org.junit.Assert.assertEquals; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.lookup.MapMessageLookup; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; import org.junit.Test; -import java.util.HashMap; -import java.util.Map; +import static org.junit.Assert.assertEquals; /** * Tests {@link MapMessageLookup} @@ -45,7 +44,7 @@ public void testStructuredDataMessageLookup() { message.put("C", "c"); // AND: An event with that message - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(message).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.DEBUG).setMessage(message).get(); // AND: A MapMessageLookup object final MapMessageLookup lookup = new MapMessageLookup(); @@ -71,7 +70,7 @@ public void testStringMapMessageLookup() { final MapMessage message = new StringMapMessage(values); // AND: An event with that message - final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(message).build(); + final LogEvent event = LogEvent.builder().setLevel(Level.DEBUG).setMessage(message).get(); // AND: A MapMessageLookup object final MapMessageLookup lookup = new MapMessageLookup(); diff --git a/log4j-script/src/main/java/org/apache/logging/log4j/script/appender/ScriptAppenderSelector.java b/log4j-script/src/main/java/org/apache/logging/log4j/script/appender/ScriptAppenderSelector.java index 189d954b8c0..34acdac2bf4 100644 --- a/log4j-script/src/main/java/org/apache/logging/log4j/script/appender/ScriptAppenderSelector.java +++ b/log4j-script/src/main/java/org/apache/logging/log4j/script/appender/ScriptAppenderSelector.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.script.appender; +import java.util.Objects; + import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; @@ -36,9 +38,6 @@ import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.script.AbstractScript; -import java.io.Serializable; -import java.util.Objects; - @Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) @Plugin public class ScriptAppenderSelector extends AbstractAppender { @@ -142,7 +141,7 @@ public static Builder newBuilder() { return new Builder(); } - private ScriptAppenderSelector(final String name, final Filter filter, final Layout layout) { + private ScriptAppenderSelector(final String name, final Filter filter, final Layout layout) { super(name, filter, layout, true, Property.EMPTY_ARRAY); } diff --git a/log4j-script/src/test/java/org/apache/logging/log4j/script/appender/routing/RoutesScriptAppenderTest.java b/log4j-script/src/test/java/org/apache/logging/log4j/script/appender/routing/RoutesScriptAppenderTest.java index 3502d54f755..3de42bbd2ab 100644 --- a/log4j-script/src/test/java/org/apache/logging/log4j/script/appender/routing/RoutesScriptAppenderTest.java +++ b/log4j-script/src/test/java/org/apache/logging/log4j/script/appender/routing/RoutesScriptAppenderTest.java @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.script.appender.routing; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; @@ -24,7 +28,7 @@ import org.apache.logging.log4j.core.appender.routing.Routes; import org.apache.logging.log4j.core.appender.routing.RoutingAppender; import org.apache.logging.log4j.core.config.AppenderControl; -import org.apache.logging.log4j.core.impl.DefaultLogEventFactory; +import org.apache.logging.log4j.core.impl.LogEventFactory; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.categories.Scripts; import org.apache.logging.log4j.core.test.junit.LoggerContextRule; @@ -37,10 +41,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -140,7 +140,8 @@ public void testRoutingAppenderRoutes() { final Routes routes = routingAppender.getRoutes(); Assert.assertNotNull(routes); Assert.assertNotNull(routes.getPatternScript()); - final LogEvent logEvent = DefaultLogEventFactory.newInstance().createEvent("", null, "", Level.ERROR, null, + final LogEventFactory factory = loggerContextRule.getConfiguration().getInstance(LogEventFactory.class); + final LogEvent logEvent = factory.createEvent("", null, "", Level.ERROR, null, null, null); assertEquals("Service2", routes.getPattern(logEvent, new ConcurrentHashMap<>())); } diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java index 91be598f94a..d82e991d755 100644 --- a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java +++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java @@ -36,8 +36,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.ValidPort; -import java.io.Serializable; - /** * Send an e-mail when a specific logging event occurs, typically on errors or * fatal errors. @@ -65,7 +63,7 @@ public final class SmtpAppender extends AbstractAppender { /** The SMTP Manager */ private final SmtpManager manager; - private SmtpAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, + private SmtpAppender(final String name, final Filter filter, final Layout layout, final boolean ignoreExceptions, Property[] properties, final SmtpManager manager) { super(name, filter, layout, ignoreExceptions, properties); this.manager = manager; @@ -237,7 +235,7 @@ public Builder setSslConfiguration(final SslConfiguration sslConfiguration) { * {@linkplain HtmlLayout#createDefaultLayout() default HTML layout}. */ @Override - public Builder setLayout(final Layout layout) { + public Builder setLayout(final Layout layout) { return super.setLayout(layout); } @@ -284,7 +282,7 @@ public static SmtpAppender createAppender(final Configuration config, final Stri final String smtpHost, final String smtpPortStr, final String smtpUsername, final String smtpPassword, final String smtpDebug, final String bufferSizeStr, - Layout layout, Filter filter, + Layout layout, Filter filter, final String ignore) { if (name == null) { LOGGER.error("No name provided for SmtpAppender"); diff --git a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java index b63a5492b82..c95a0e06a06 100644 --- a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java +++ b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java @@ -16,22 +16,25 @@ */ package org.apache.logging.log4j.smtp.appender; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - +import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.async.RingBufferLogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.ContextDataFactory; +import org.apache.logging.log4j.core.impl.DefaultContextDataFactory; import org.apache.logging.log4j.core.impl.MementoMessage; import org.apache.logging.log4j.core.impl.MutableLogEvent; -import org.apache.logging.log4j.core.time.ClockFactory; +import org.apache.logging.log4j.core.impl.ThreadContextDataInjector; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.SystemClock; import org.apache.logging.log4j.message.ReusableMessage; import org.apache.logging.log4j.message.ReusableSimpleMessage; import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Unit tests for {@link SmtpManager}. */ @@ -56,15 +59,15 @@ private void testAdd(LogEvent event) { // LOG4J2-3172: make sure existing protections are not violated @Test - void testAdd_WhereLog4jLogEventWithReusableMessage() { - LogEvent event = new Log4jLogEvent.Builder().setMessage(getReusableMessage("test message")).build(); + void testAdd_WhereImmutableLogEventWithReusableMessage() { + LogEvent event = LogEvent.builder().setMessage(getReusableMessage("test message")).get(); testAdd(event); } // LOG4J2-3172: make sure existing protections are not violated @Test void testAdd_WhereMutableLogEvent() { - MutableLogEvent event = new MutableLogEvent(new StringBuilder("test message"), null); + MutableLogEvent event = new MutableLogEvent(new DefaultContextDataFactory(), new StringBuilder("test message"), null); testAdd(event); } @@ -72,7 +75,9 @@ void testAdd_WhereMutableLogEvent() { @Test void testAdd_WhereRingBufferLogEvent() { RingBufferLogEvent event = new RingBufferLogEvent(); - event.setValues(null, null, null, null, null, getReusableMessage("test message"), null, null, null, 0, null, 0, null, ClockFactory.getClock(), new DummyNanoClock()); + ContextDataFactory contextDataFactory = new DefaultContextDataFactory(); + ContextDataInjector contextDataInjector = ThreadContextDataInjector.create(contextDataFactory); + event.setValues(null, null, null, null, null, getReusableMessage("test message"), null, null, null, 0, null, 0, null, new SystemClock(), new DummyNanoClock(), contextDataFactory, contextDataInjector); testAdd(event); } diff --git a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootLoggingSystem.java b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootLoggingSystem.java index cfe443abbdc..ff5e710772e 100644 --- a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootLoggingSystem.java +++ b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootLoggingSystem.java @@ -16,20 +16,14 @@ */ package org.apache.logging.log4j.spring.boot; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; -import java.net.URLConnection; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Properties; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,15 +31,14 @@ import org.apache.logging.log4j.core.config.AbstractConfiguration; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationResolver; import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; -import org.apache.logging.log4j.core.net.UrlConnectionFactory; -import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; -import org.apache.logging.log4j.core.util.AuthorizationProvider; -import org.apache.logging.log4j.core.util.FileUtils; +import org.apache.logging.log4j.core.impl.Log4jProperties; +import org.apache.logging.log4j.plugins.di.Injector; +import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.status.StatusLogger; -import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.PropertyResolver; import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingSystem; @@ -72,9 +65,15 @@ public class Log4j2SpringBootLoggingSystem extends Log4J2LoggingSystem { private static final String OVERRIDE_PARAM = "override"; private static final Logger LOGGER = StatusLogger.getLogger(); private static final int PRECEDENCE = 0; + private final PropertyResolver propertyResolver; public Log4j2SpringBootLoggingSystem(ClassLoader loader) { + this(loader, org.apache.logging.log4j.spi.LoggingSystem.getPropertyResolver()); + } + + public Log4j2SpringBootLoggingSystem(ClassLoader loader, PropertyResolver resolver) { super(loader); + propertyResolver = resolver; } /** @@ -88,22 +87,24 @@ public Log4j2SpringBootLoggingSystem(ClassLoader loader) { @Override public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) { Environment environment = initializationContext.getEnvironment(); - PropertiesUtil.getProperties().addPropertySource(new SpringPropertySource(environment)); - getLoggerContext().putObjectIfAbsent(ENVIRONMENT_KEY, environment); + propertyResolver.addSource(new SpringPropertySource(environment)); + final LoggerContext loggerContext = getLoggerContext(); + loggerContext.getInjector().registerBinding(Key.forClass(Environment.class), initializationContext::getEnvironment); + // TODO(ms): replace use of putObject (or update to use) with Injector bindings directly + loggerContext.putObjectIfAbsent(ENVIRONMENT_KEY, environment); super.initialize(initializationContext, configLocation, logFile); } @Override protected String[] getStandardConfigLocations() { - String[] locations = super.getStandardConfigLocations(); - PropertiesUtil props = new PropertiesUtil(new Properties()); - String location = props.getStringProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - if (location != null) { - List list = new ArrayList<>(Arrays.asList(super.getStandardConfigLocations())); - list.add(location); - locations = list.toArray(new String[0]); - } - return locations; + final String[] locations = super.getStandardConfigLocations(); + return propertyResolver.getString(Log4jProperties.CONFIG_LOCATION) + .map(location -> { + final String[] copy = Arrays.copyOf(locations, locations.length + 1); + copy[locations.length] = location; + return copy; + }) + .orElse(locations); } /** @@ -152,20 +153,22 @@ protected void loadConfiguration(String location, LogFile logFile, List if (overrides != null) { locations.addAll(overrides); } + final Injector injector = ctx.getInjector(); + final ConfigurationResolver resolver = injector.getInstance(ConfigurationResolver.class); + final ConfigurationFactory configurationFactory = injector.getInstance(ConfigurationFactory.KEY); if (locations.size() == 1) { final URL url = ResourceUtils.getURL(location); - final ConfigurationSource source = getConfigurationSource(url); - if (source != null) { - ctx.start(ConfigurationFactory.getInstance().getConfiguration(ctx, source)); - } + resolver.tryResolve(url) + .ifPresent(source -> ctx.start(configurationFactory.getConfiguration(ctx, source))); } else { final List configs = new ArrayList<>(); boolean first = true; for (final String sourceLocation : locations) { - final ConfigurationSource source = getConfigurationSource(ResourceUtils.getURL(sourceLocation)); + final ConfigurationSource source = resolver.tryResolve(ResourceUtils.getURL(sourceLocation)) + .orElse(null); if (source != null) { try { - final Configuration config = ConfigurationFactory.getInstance().getConfiguration(ctx, source); + final Configuration config = configurationFactory.getConfiguration(ctx, source); if (config instanceof AbstractConfiguration) { configs.add((AbstractConfiguration) config); } else { @@ -225,26 +228,6 @@ private List parseConfigLocations(String configLocations) { return locations; } - private ConfigurationSource getConfigurationSource(URL url) throws IOException, URISyntaxException { - AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties()); - SslConfiguration sslConfiguration = url.getProtocol().equals(HTTPS) - ? SslConfigurationFactory.getSslConfiguration() : null; - URLConnection urlConnection = UrlConnectionFactory.createConnection(url, 0, sslConfiguration, - provider); - - File file = FileUtils.fileFromUri(url.toURI()); - try { - if (file != null) { - return new ConfigurationSource(urlConnection.getInputStream(), FileUtils.fileFromUri(url.toURI())); - } else { - return new ConfigurationSource(urlConnection.getInputStream(), url, urlConnection.getLastModified()); - } - } catch (FileNotFoundException ex) { - LOGGER.info("Unable to locate file {}, ignoring.", url.toString()); - return null; - } - } - private LoggerContext getLoggerContext() { return (LoggerContext) LogManager.getContext(false); } @@ -254,10 +237,11 @@ public static class Factory implements LoggingSystemFactory { @Override public LoggingSystem getLoggingSystem(ClassLoader classLoader) { - if (PropertiesUtil.getProperties().getBooleanProperty(LOG4J2_DISABLE_CLOUD_CONFIG_LOGGING_SYSTEM)) { + final PropertyResolver resolver = org.apache.logging.log4j.spi.LoggingSystem.getPropertyResolver(); + if (resolver.getBoolean(LOG4J2_DISABLE_CLOUD_CONFIG_LOGGING_SYSTEM)) { return null; } - return new Log4j2SpringBootLoggingSystem(classLoader); + return new Log4j2SpringBootLoggingSystem(classLoader, resolver); } } diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java index d795ee4239d..cb8d4324e70 100644 --- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java +++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java @@ -23,7 +23,6 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.StringFormatterMessageFactory; -import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.spi.LoggingSystem; import org.junit.Before; import org.junit.Test; diff --git a/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java b/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java index f7b88d46913..000d9a35b27 100644 --- a/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java +++ b/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.web.appender; +import javax.servlet.ServletContext; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -30,9 +32,6 @@ import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.web.WebLoggerContextUtils; -import javax.servlet.ServletContext; -import java.io.Serializable; - /** * Logs using the ServletContext's log method */ @@ -57,9 +56,9 @@ public ServletAppender build() { LOGGER.error("No servlet context is available"); return null; } - Layout layout = getLayout(); + Layout layout = getLayout(); if (layout == null) { - layout = PatternLayout.createDefaultLayout(); + layout = PatternLayout.createDefaultLayout(WebLoggerContextUtils.getWebLoggerContext(servletContext).getConfiguration()); } else if (!(layout instanceof AbstractStringLayout)) { LOGGER.error("Layout must be a StringLayout to log to ServletContext"); return null; @@ -94,7 +93,7 @@ public static > B newBuilder() { private final ServletContext servletContext; private final boolean logThrowables; - private ServletAppender(final String name, final Layout layout, final Filter filter, + private ServletAppender(final String name, final Layout layout, final Filter filter, final ServletContext servletContext, final boolean ignoreExceptions, final boolean logThrowables, Property[] properties) { super(name, filter, layout, ignoreExceptions, properties); diff --git a/pom.xml b/pom.xml index c339976f9fa..f0407e44bcf 100644 --- a/pom.xml +++ b/pom.xml @@ -1654,6 +1654,19 @@ check + + apply-spotless + + apply + + process-sources + + apply-spotless-test + + apply + + process-test-sources + diff --git a/src/site/asciidoc/faq.adoc b/src/site/asciidoc/faq.adoc index d7038ac0aa6..2ab98ec452e 100644 --- a/src/site/asciidoc/faq.adoc +++ b/src/site/asciidoc/faq.adoc @@ -271,6 +271,9 @@ the ``2'' in the file name! (See the link:manual/configuration.html#AutomaticConfiguration[configuration manual page] for more details.) +From log4j-3.0.0 onward:: +Define the property `log4j2.*.System.debug` or set it to `true` (ignoring case) to enable internal logging to the console. + From log4j-2.9 onward:: From log4j-2.9 onward, log4j2 will print all internal logging to the console if system property `log4j2.debug` is either defined empty or its value diff --git a/src/site/asciidoc/manual/extending.adoc b/src/site/asciidoc/manual/extending.adoc index 70704130b3f..d8ab942aa1f 100644 --- a/src/site/asciidoc/manual/extending.adoc +++ b/src/site/asciidoc/manual/extending.adoc @@ -55,10 +55,10 @@ optionally, a link:../log4j-core/apidocs/org/apache/logging/log4j/spi/ThreadCont .. Create a `META-INF/services/org.apache.logging.spi.Provider` file that contains the name of the class that implements `org.apache.logging.spi.Provider`. -2. Setting the system property "log4j2.loggerContextFactory" to the name +2. Setting the system property `log4j2.*.LoggerContext.factory` to the name of the `LoggerContextFactory` class to use. -3. Setting the property "log4j2.loggerContextFactory" in a properties -file named "log4j2.LogManager.properties" to the name of the +3. Setting the property `log4j2.*.LoggerContext.factory` in a properties +file named "log4j2.component.properties" to the name of the LoggerContextFactory class to use. The properties file must be on the classpath. @@ -371,7 +371,7 @@ pause while the reconfiguration takes place. public final class StubAppender extends AbstractOutputStreamAppender { private StubAppender(String name, - Layout layout, + Layout layout, Filter filter, boolean ignoreExceptions, StubManager manager) { @@ -514,7 +514,7 @@ public static ListAppender createAppender( @PluginAttribute @Required(message = "No name provided for ListAppender") final String name, @PluginAttribute final boolean entryPerNewLine, @PluginAttribute final boolean raw, - @PluginElement final Layout layout, + @PluginElement final Layout layout, @PluginElement final Filter filter) { return new ListAppender(name, filter, layout, newLine, raw); } @@ -534,7 +534,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private String name; private boolean entryPerNewLine; private boolean raw; - private Layout layout; + private Layout layout; private Filter filter; @@ -556,7 +556,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui return this; } - public Builder setLayout(@PluginElement final Layout layout) { + public Builder setLayout(@PluginElement final Layout layout) { this.layout = layout; return this; } diff --git a/src/site/asciidoc/manual/garbagefree.adoc b/src/site/asciidoc/manual/garbagefree.adoc index d08a9564a4a..b5e0e4cece5 100644 --- a/src/site/asciidoc/manual/garbagefree.adoc +++ b/src/site/asciidoc/manual/garbagefree.adoc @@ -86,7 +86,7 @@ reference these fields after the web application is undeployed. To avoid causing memory leaks, Log4j will not use these ThreadLocals when it detects that it is used in a web application (when the `javax.servlet.Servlet` class is in the classpath, or when system -property `log4j2.isWebapp` is set to "true"). +property `log4j2.*.Web.enableWebApp` is set to "true"). Some garbage-reducing functionality does not rely on ThreadLocals and is enabled by default for all applications: in Log4j 2.6, converting log @@ -116,7 +116,7 @@ you may also configure a link:async.html#WaitStrategy[custom wait strategy].) There are two separate system properties for manually controlling the mechanisms Log4j uses to avoid creating temporary objects: -* `log4j2.enableThreadlocals` - if "true" (the default for non-web +* `log4j2.*.GC.enableThreadLocals` - if "true" (the default for non-web applications) objects are stored in ThreadLocal fields and reused, otherwise new objects are created for each log event. * `log4j2.enableDirectEncoders` - if "true" (the default) log events are @@ -389,7 +389,7 @@ interface. If an object is logged that implements this interface, its Log4j may call `toString()` on message and parameter objects when garbage-free logging is disabled (when system property -`log4j2.enableThreadlocals` is set to "false".) +`log4j2.*.GC.enableThreadLocals` is set to "false".) [#codeImpact] === Impact on Application Code: Autoboxing diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm index f1bb103a21e..6055ce9723c 100644 --- a/src/site/asciidoc/manual/json-template-layout.adoc.vm +++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm @@ -1044,7 +1044,7 @@ Resolves `logEvent.getMessage().getParameters()`. Regarding garbage footprint, `stringified` flag translates to `String.valueOf(value)`, hence mind not-`String`-typed values. Further, `logEvent.getMessage()` is expected to implement `ParameterVisitable` interface, -which is the case if `log4j2.enableThreadLocals` property set to true. +which is the case if `log4j2.*.GC.enableThreadLocals` property set to true. ==== Resolve the message parameters into an array: