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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions log4j-async-logger/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,21 @@
<name>Apache Log4j Async Logger</name>
<description>Alternative implementation of logger that uses LMAX Disruptor.</description>

<properties>
<bnd-extra-package-options>
<!-- JSpecify is optional at runtime -->
org.jspecify.annotations.*;resolution:=optional
</bnd-extra-package-options>
</properties>

<dependencies>

<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@
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.kit.logger.AbstractLogger;
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.AbstractLogger;
import org.apache.logging.log4j.spi.recycler.Recycler;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.StringMap;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* AsyncLogger is a logger designed for high throughput and low latency logging. It does not perform any I/O in the
Expand All @@ -59,6 +63,7 @@
* and they will flush to disk at the end of each batch. This means that even with immediateFlush=false, there will
* never be any items left in the buffer; all log events will all be written to disk in a very efficient manner.
*/
@NullMarked
public class AsyncLogger extends Logger {
// Implementation note: many methods in this class are tuned for performance. MODIFY WITH CARE!
// Specifically, try to keep the hot methods to 35 bytecodes or less:
Expand Down Expand Up @@ -86,8 +91,11 @@ public class AsyncLogger extends Logger {
final LoggerContext context,
final String name,
final MessageFactory messageFactory,
final FlowMessageFactory flowMessageFactory,
final RecyclerFactory recyclerFactory,
final org.apache.logging.log4j.Logger statusLogger,
final AsyncLoggerDisruptor loggerDisruptor) {
super(context, name, messageFactory);
super(context, name, messageFactory, flowMessageFactory, recyclerFactory, statusLogger);
final Configuration configuration = context.getConfiguration();
this.translatorRecycler = configuration
.getRecyclerFactory()
Expand All @@ -107,7 +115,7 @@ public class AsyncLogger extends Logger {
@Override
protected void updateConfiguration(final Configuration newConfig) {
nanoClock = newConfig.getNanoClock();
includeLocation = newConfig.getLoggerConfig(name).isIncludeLocation();
includeLocation = newConfig.getLoggerConfig(getName()).isIncludeLocation();
super.updateConfiguration(newConfig);
}

Expand Down Expand Up @@ -149,26 +157,26 @@ public void logMessage(
* This re-uses a {@code RingBufferLogEventTranslator} instance cached in a {@code ThreadLocal} to avoid creating
* unnecessary objects with each event.
*
* @param fqcn fully qualified name of the caller
* @param location the Location of the caller.
* @param level level at which the caller wants to log the message
* @param marker message marker
* @param message the log message
* @param thrown a {@code Throwable} or {@code null}
* @param fqcn fully qualified name of the caller
* @param location the Location of the caller.
* @param level level at which the caller wants to log the message
* @param marker message marker
* @param message the log message
* @param throwable a {@code Throwable} or {@code null}
*/
@Override
public void log(
final Level level,
final Marker marker,
protected void doLog(
final String fqcn,
final StackTraceElement location,
final @Nullable StackTraceElement location,
final Level level,
final @Nullable Marker marker,
final Message message,
final Throwable thrown) {
final @Nullable Throwable throwable) {
// Implementation note: this method is tuned for performance. MODIFY WITH CARE!

final RingBufferLogEventTranslator translator = translatorRecycler.acquire();
try {
initTranslator(translator, fqcn, location, level, marker, message, thrown);
initTranslator(translator, fqcn, location, level, marker, message, throwable);
translator.updateThreadValues();
publish(translator);
} finally {
Expand Down Expand Up @@ -220,7 +228,7 @@ private void initTranslator(

translator.setBasicValues(
this,
name,
getName(),
marker,
fqcn,
level,
Expand All @@ -246,7 +254,7 @@ private void initTranslator(

translator.setBasicValues(
this,
name,
getName(),
marker,
fqcn,
level,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.kit.logger.AbstractLogger;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginFactory;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.util.Strings;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
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.message.FlowMessageFactory;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.status.StatusLogger;

/**
Expand Down Expand Up @@ -78,8 +80,15 @@ private AsyncWaitStrategyFactory createAsyncWaitStrategyFactory() {
}

@Override
protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
return new AsyncLogger(ctx, name, messageFactory, loggerDisruptor);
protected Logger newInstance(
final LoggerContext ctx,
final String name,
final MessageFactory messageFactory,
final FlowMessageFactory flowMessageFactory,
final RecyclerFactory recyclerFactory,
final org.apache.logging.log4j.Logger statusLogger) {
return new AsyncLogger(
ctx, name, messageFactory, flowMessageFactory, recyclerFactory, statusLogger, loggerDisruptor);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.CoreLoggerContexts;
import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
import org.apache.logging.log4j.internal.recycler.DummyRecyclerFactoryProvider;
import org.apache.logging.log4j.status.StatusLogger;
import org.junit.Test;
import org.junit.experimental.categories.Category;

Expand All @@ -30,7 +32,14 @@ public class AsyncLoggerContextTest {

@Test
public void testNewInstanceReturnsAsyncLogger() {
final Logger logger = new AsyncLoggerContext("a").newInstance(new LoggerContext("a"), "a", null);
final Logger logger = new AsyncLoggerContext("a")
.newInstance(
new LoggerContext("a"),
"a",
null,
null,
new DummyRecyclerFactoryProvider().createForEnvironment(null),
StatusLogger.getLogger());
assertTrue(logger instanceof AsyncLogger);

CoreLoggerContexts.stopLoggerContext(); // stop async thread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.core.test.junit.ContextSelectorType;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.kit.logger.AbstractLogger;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ReusableSimpleMessage;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.SetSystemProperty;
Expand Down
5 changes: 5 additions & 0 deletions log4j-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
com.lmax.disruptor.*;resolution:=optional,
org.apache.commons.compress.*;resolution:=optional,
org.fusesource.jansi;resolution:=optional,
org.jspecify.annotations.*;resolution:=optional,
<!-- Optional Java modules -->
<!-- java.management -->
java.lang.management;resolution:=optional,
Expand Down Expand Up @@ -69,6 +70,10 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-kit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-plugins</artifactId>
Expand Down
68 changes: 31 additions & 37 deletions log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
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.kit.logger.AbstractLogger;
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;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.util.Strings;
import org.apache.logging.log4j.util.Supplier;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* The core implementation of the {@link org.apache.logging.log4j.Logger} interface. Besides providing an implementation
Expand All @@ -43,40 +46,37 @@
* 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.
*/
@NullMarked
public class Logger extends AbstractLogger implements Supplier<LoggerConfig> {

/**
* Config should be consistent across threads.
*/
protected volatile PrivateConfig privateConfig;

// FIXME: ditto to the above
private final LoggerContext context;

/**
* The constructor.
*
* @param context The LoggerContext this Logger is associated with.
* @param messageFactory The message factory.
* @param name The name of the Logger.
* @param messageFactory The message factory to use for logging methods.
* @param flowMessageFactory The flow message factory to use for flow logging methods.
* @param recyclerFactory The recycler to use for log builder instances.
*/
protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) {
super(name, messageFactory);
protected Logger(
final LoggerContext context,
final String name,
final MessageFactory messageFactory,
final FlowMessageFactory flowMessageFactory,
final RecyclerFactory recyclerFactory,
final org.apache.logging.log4j.Logger statusLogger) {
super(name, messageFactory, flowMessageFactory, recyclerFactory, statusLogger);
this.context = context;
privateConfig = new PrivateConfig(context.getConfiguration(), this);
}

/**
* This is used to construct an InternalLoggerContext, which makes SimpleLoggerContext conmpatible with core.
* @param context the InternalLoggerContext.
* @param name the Logger name.
*/
protected Logger(final LoggerContext context, final String name) {
super(name);
this.context = context;
privateConfig = null;
}

/**
* This method is only used for 1.x compatibility. Returns the parent of this Logger. If it doesn't already exist
* return a temporary Logger.
Expand All @@ -95,10 +95,7 @@ private Logger getParent(final PrivateConfig config) {
}
final String lcName = lc.getName();
final MessageFactory messageFactory = getMessageFactory();
if (context.hasLogger(lcName, messageFactory)) {
return context.getLogger(lcName, messageFactory);
}
return new Logger(context, lcName, messageFactory);
return context.getLogger(lcName, messageFactory);
}

/**
Expand Down Expand Up @@ -149,35 +146,32 @@ protected boolean requiresLocation() {
}

@Override
public void logMessage(
final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) {
final Message msg = message == null ? new SimpleMessage(Strings.EMPTY) : message;
final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
strategy.log(this, getName(), fqcn, marker, level, msg, t);
}

@Override
protected void log(
final Level level,
final Marker marker,
protected void doLog(
final String fqcn,
final StackTraceElement location,
final Message message,
final Throwable throwable) {
final @Nullable StackTraceElement location,
final Level level,
final @Nullable Marker marker,
final @Nullable Message message,
final @Nullable Throwable throwable) {
final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
strategy.log(this, getName(), fqcn, location, marker, level, message, throwable);
}

@Override
public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) {
return privateConfig.filter(level, marker, message, t);
public boolean isEnabled(final Level level, final Marker marker) {
return privateConfig.filter(level, marker, null);
}

@Override
public boolean isEnabled(final Level level, final Marker marker, final String message) {
return privateConfig.filter(level, marker, message);
}

@Override
public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) {
return privateConfig.filter(level, marker, message, t);
}

@Override
public boolean isEnabled(final Level level, final Marker marker, final String message, final Object... params) {
return privateConfig.filter(level, marker, message, params);
Expand Down
Loading