You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2015/09/19 22:53:37 UTC

[4/6] logging-log4j2 git commit: LOG4J2-1121 Logger (and AsyncLogger) delegate logging to their LoggerConfig's ReliabilityStrategy

LOG4J2-1121 Logger (and AsyncLogger) delegate logging to their
LoggerConfig's ReliabilityStrategy

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/1e017cbb
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/1e017cbb
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/1e017cbb

Branch: refs/heads/LOG4J2-1121B-ReliabilityStrategy
Commit: 1e017cbbf20c1df1378615210451589f8ca408aa
Parents: 86dde4e
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 20 05:34:23 2015 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 20 05:34:23 2015 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/core/Logger.java   |  18 ++-
 .../logging/log4j/core/async/AsyncLogger.java   |   8 +-
 .../logging/log4j/core/config/LoggerConfig.java | 155 ++++++-------------
 .../log4j/core/async/AsyncLoggerConfigTest.java |   6 +-
 4 files changed, 71 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e017cbb/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
----------------------------------------------------------------------
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 486b18b..07def0f 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
@@ -26,12 +26,14 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.core.config.Configuration;
 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.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.util.Strings;
+import org.apache.logging.log4j.util.Supplier;
 
 /**
  * The core implementation of the {@link org.apache.logging.log4j.Logger} interface. Besides providing an
@@ -46,7 +48,7 @@ import org.apache.logging.log4j.util.Strings;
  * 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 {
+public class Logger extends AbstractLogger implements Supplier<LoggerConfig> {
 
     private static final long serialVersionUID = 1L;
 
@@ -116,12 +118,24 @@ public class Logger extends AbstractLogger {
         }
         privateConfig = new PrivateConfig(privateConfig, actualLevel);
     }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.logging.log4j.util.Supplier#get()
+     */
+    public LoggerConfig get() {
+        return privateConfig.loggerConfig;
+    }
 
     @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;
+        
+        // check if we need to reconfigure
         privateConfig.config.getConfigurationMonitor().checkConfiguration();
-        privateConfig.loggerConfig.log(getName(), fqcn, marker, level, msg, t);
+        
+        final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
+        strategy.log(this, getName(), fqcn, marker, level, msg, t);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e017cbb/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
----------------------------------------------------------------------
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 927e80b..8300a97 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
@@ -27,6 +27,7 @@ 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.config.Property;
+import org.apache.logging.log4j.core.config.ReliabilityStrategy;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
 import org.apache.logging.log4j.core.util.Clock;
@@ -193,6 +194,7 @@ public class AsyncLogger extends Logger {
             return null;
         }
         try {
+            @SuppressWarnings("unchecked")
             final ExceptionHandler<RingBufferLogEvent> result = Loader.newCheckedInstanceOf(cls, ExceptionHandler.class);
             LOGGER.debug("AsyncLogger.ExceptionHandler={}", result);
             return result;
@@ -284,7 +286,8 @@ public class AsyncLogger extends Logger {
             final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) {
         if (info.isAppenderThread && theDisruptor.getRingBuffer().remainingCapacity() == 0) {
             // bypass RingBuffer and invoke Appender directly
-            privateConfig.loggerConfig.log(getName(), fqcn, marker, level, message, thrown);
+            final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
+            strategy.log(this, getName(), fqcn, marker, level, message, thrown);
             return true;
         }
         return false;
@@ -382,7 +385,8 @@ public class AsyncLogger extends Logger {
     public void actualAsyncLog(final RingBufferLogEvent event) {
         final Map<Property, Boolean> properties = privateConfig.loggerConfig.getProperties();
         event.mergePropertiesIntoContextMap(properties, privateConfig.config.getStrSubstitutor());
-        privateConfig.logEvent(event);
+        final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
+        strategy.log(this, event);
     }
 
     public static void stop() {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e017cbb/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index faca562..1b1f9e7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -25,12 +25,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.TimeUnit;
-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.LogManager;
@@ -64,7 +58,6 @@ public class LoggerConfig extends AbstractFilterable {
 
     private static final long serialVersionUID = 1L;
 
-    private static final int MAX_RETRIES = 3;
     private static LogEventFactory LOG_EVENT_FACTORY = null;
 
     private List<AppenderRef> appenderRefs = new ArrayList<>();
@@ -75,12 +68,9 @@ public class LoggerConfig extends AbstractFilterable {
     private boolean additive = true;
     private boolean includeLocation = true;
     private LoggerConfig parent;
-    private final AtomicInteger counter = new AtomicInteger();
-    private final AtomicBoolean shutdown = new AtomicBoolean(false);
     private final Map<Property, Boolean> properties;
     private final Configuration config;
-    private final Lock shutdownLock = new ReentrantLock();
-    private final Condition noLogEvents = shutdownLock.newCondition(); // should only be used when shutdown == true
+    private final ReliabilityStrategy reliabilityStrategy;
 
     static {
         final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
@@ -108,6 +98,7 @@ public class LoggerConfig extends AbstractFilterable {
         this.name = Strings.EMPTY;
         this.properties = null;
         this.config = null;
+        this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
     }
 
     /**
@@ -117,20 +108,18 @@ public class LoggerConfig extends AbstractFilterable {
      * @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) {
+    public LoggerConfig(final String name, final Level level, final boolean additive) {
         this.logEventFactory = LOG_EVENT_FACTORY;
         this.name = name;
         this.level = level;
         this.additive = additive;
         this.properties = null;
         this.config = null;
+        this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
     }
 
-    protected LoggerConfig(final String name,
-            final List<AppenderRef> appenders, final Filter filter,
-            final Level level, final boolean additive,
-            final Property[] properties, final Configuration config,
+    protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter,
+            final Level level, final boolean additive, final Property[] properties, final Configuration config,
             final boolean includeLocation) {
         super(filter);
         this.logEventFactory = LOG_EVENT_FACTORY;
@@ -149,6 +138,7 @@ public class LoggerConfig extends AbstractFilterable {
         } else {
             this.properties = null;
         }
+        this.reliabilityStrategy = config.getConfigurationMonitor().getReliabilityStrategy(this);
     }
 
     @Override
@@ -190,8 +180,7 @@ public class LoggerConfig extends AbstractFilterable {
      * @param level The Level to use.
      * @param filter A Filter for the Appender reference.
      */
-    public void addAppender(final Appender appender, final Level level,
-            final Filter filter) {
+    public void addAppender(final Appender appender, final Level level, final Filter filter) {
         appenders.add(new AppenderControl(appender, level, filter));
     }
 
@@ -213,8 +202,7 @@ public class LoggerConfig extends AbstractFilterable {
     /**
      * Returns all Appenders as a Map.
      *
-     * @return a Map with the Appender name as the key and the Appender as the
-     *         value.
+     * @return a Map with the Appender name as the key and the Appender as the value.
      */
     public Map<String, Appender> getAppenders() {
         final Map<String, Appender> map = new HashMap<>();
@@ -228,7 +216,6 @@ public class LoggerConfig extends AbstractFilterable {
      * Removes all Appenders.
      */
     protected void clearAppenders() {
-        waitForCompletion();
         List<AppenderControl> copy = new ArrayList<>(appenders);
         while (!copy.isEmpty()) {
             appenders.removeAll(copy);
@@ -284,8 +271,7 @@ public class LoggerConfig extends AbstractFilterable {
     }
 
     /**
-     * Sets the LogEventFactory. Usually the LogEventFactory will be this
-     * LoggerConfig.
+     * Sets the LogEventFactory. Usually the LogEventFactory will be this LoggerConfig.
      *
      * @param logEventFactory the LogEventFactory.
      */
@@ -305,17 +291,15 @@ public class LoggerConfig extends AbstractFilterable {
     /**
      * Sets the additive setting.
      *
-     * @param additive true if the LoggerConfig should be additive, false
-     *            otherwise.
+     * @param additive true if the LoggerConfig should be additive, false otherwise.
      */
     public void setAdditive(final boolean additive) {
         this.additive = additive;
     }
 
     /**
-     * Returns the value of logger configuration attribute {@code includeLocation},
-     * or, if no such attribute was configured, {@code true} if logging is
-     * synchronous or {@code false} if logging is asynchronous.
+     * Returns the value of logger configuration attribute {@code includeLocation}, or, if no such attribute was
+     * configured, {@code true} if logging is synchronous or {@code false} if logging is asynchronous.
      *
      * @return whether location should be passed downstream
      */
@@ -324,22 +308,19 @@ public class LoggerConfig extends AbstractFilterable {
     }
 
     /**
-     * Returns an unmodifiable map with the configuration properties, or
-     * {@code null} if this {@code LoggerConfig} does not have any configuration
-     * properties.
+     * Returns an unmodifiable map with the configuration properties, or {@code null} if this {@code LoggerConfig} does
+     * not have any configuration properties.
      * <p>
-     * For each {@code Property} key in the map, the value is {@code true} if
-     * the property value has a variable that needs to be substituted.
+     * For each {@code Property} key in the map, the value is {@code true} if the property value has a variable that
+     * needs to be substituted.
      *
-     * @return an unmodifiable map with the configuration properties, or
-     *         {@code null}
+     * @return an unmodifiable map with the configuration properties, or {@code null}
      * @see Configuration#getStrSubstitutor()
      * @see StrSubstitutor
      */
     // LOG4J2-157
     public Map<Property, Boolean> getProperties() {
-        return properties == null ? null : Collections
-                .unmodifiableMap(properties);
+        return properties == null ? null : Collections.unmodifiableMap(properties);
     }
 
     /**
@@ -352,9 +333,8 @@ public class LoggerConfig extends AbstractFilterable {
      * @param data The Message.
      * @param t A Throwable or null.
      */
-    public void log(final String loggerName, final String fqcn,
-            final Marker marker, final Level level, final Message data,
-            final Throwable t) {
+    public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
+            final Message data, final Throwable t) {
         List<Property> props = null;
         if (properties != null) {
             props = new ArrayList<>(properties.size());
@@ -364,8 +344,8 @@ public class LoggerConfig extends AbstractFilterable {
             LogEvent event = builder.build();
             for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
                 final Property prop = entry.getKey();
-                final String value = entry.getValue() ? config.getStrSubstitutor()
-                        .replace(event, prop.getValue()) : prop.getValue();
+                final String value = entry.getValue() ? config.getStrSubstitutor().replace(event, prop.getValue())
+                        : prop.getValue();
                 props.add(Property.createProperty(prop.getName(), value));
             }
         }
@@ -373,63 +353,24 @@ public class LoggerConfig extends AbstractFilterable {
     }
 
     /**
-     * Waits for all log events to complete before shutting down this
-     * loggerConfig.
-     */
-    private void waitForCompletion() {
-        shutdownLock.lock();
-        try {
-            if (shutdown.compareAndSet(false, true)) {
-                int retries = 0;
-                while (counter.get() > 0) {
-                    try {
-                        noLogEvents.await(retries + 1, TimeUnit.SECONDS);
-                    } catch (final InterruptedException ie) {
-                        if (++retries > MAX_RETRIES) {
-                            break;
-                        }
-                    }
-                }
-            }
-        } finally {
-            shutdownLock.unlock();
-        }
-    }
-
-    /**
      * Logs an event.
      *
      * @param event The log event.
      */
     public void log(final LogEvent event) {
-        beforeLogEvent();
-        try {
-            if (!isFiltered(event)) {
-                processLogEvent(event);
-            }
-        } finally {
-            afterLogEvent();
+        if (!isFiltered(event)) {
+            processLogEvent(event);
         }
     }
-
-    private void beforeLogEvent() {
-        counter.incrementAndGet();
-    }
-
-    private void afterLogEvent() {
-        if (counter.decrementAndGet() == 0 && shutdown.get()) {
-            signalCompletionIfShutdown();
-        }
-    }
-
-    private void signalCompletionIfShutdown() {
-        final Lock lock = shutdownLock;
-        lock.lock();
-        try {
-            noLogEvents.signalAll();
-        } finally {
-            lock.unlock();
-        }
+    
+    /**
+     * Returns the object responsible for ensuring log events are delivered to a working appender, even during or after
+     * a reconfiguration.
+     * 
+     * @return the object responsible for delivery of log events to the appender
+     */
+    public ReliabilityStrategy getReliabilityStrategy() {
+        return reliabilityStrategy;
     }
 
     private void processLogEvent(final LogEvent event) {
@@ -469,14 +410,11 @@ public class LoggerConfig extends AbstractFilterable {
      * @return A new LoggerConfig.
      */
     @PluginFactory
-    public static LoggerConfig createLogger(
-            @PluginAttribute("additivity") final String additivity,
-            @PluginAttribute("level") final Level level,
-            @PluginAttribute("name") final String loggerName,
+    public static LoggerConfig createLogger(@PluginAttribute("additivity") final String additivity,
+            @PluginAttribute("level") final Level level, @PluginAttribute("name") final String loggerName,
             @PluginAttribute("includeLocation") final String includeLocation,
             @PluginElement("AppenderRef") final AppenderRef[] refs,
-            @PluginElement("Properties") final Property[] properties,
-            @PluginConfiguration final Configuration config,
+            @PluginElement("Properties") final Property[] properties, @PluginConfiguration final Configuration config,
             @PluginElement("Filter") final Filter filter) {
         if (loggerName == null) {
             LOGGER.error("Loggers cannot be configured without a name");
@@ -487,16 +425,16 @@ public class LoggerConfig extends AbstractFilterable {
         final String name = loggerName.equals("root") ? Strings.EMPTY : loggerName;
         final boolean additive = Booleans.parseBoolean(additivity, true);
 
-        return new LoggerConfig(name, appenderRefs, filter, level, additive,
-                properties, config, includeLocation(includeLocation));
+        return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config,
+                includeLocation(includeLocation));
     }
 
     // Note: for asynchronous loggers, includeLocation default is FALSE,
     // for synchronous loggers, includeLocation default is TRUE.
     protected static boolean includeLocation(final String includeLocationConfigValue) {
         if (includeLocationConfigValue == null) {
-            final boolean sync = !AsyncLoggerContextSelector.class.getName()
-                    .equals(PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR));
+            final boolean sync = !AsyncLoggerContextSelector.class.getName().equals(
+                    PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR));
             return sync;
         }
         return Boolean.parseBoolean(includeLocationConfigValue);
@@ -511,21 +449,18 @@ public class LoggerConfig extends AbstractFilterable {
         private static final long serialVersionUID = 1L;
 
         @PluginFactory
-        public static LoggerConfig createLogger(
-                @PluginAttribute("additivity") final String additivity,
+        public static LoggerConfig createLogger(@PluginAttribute("additivity") final String additivity,
                 @PluginAttribute("level") final Level level,
                 @PluginAttribute("includeLocation") final String includeLocation,
                 @PluginElement("AppenderRef") final AppenderRef[] refs,
                 @PluginElement("Properties") final Property[] properties,
-                @PluginConfiguration final Configuration config,
-                @PluginElement("Filter") final Filter filter) {
+                @PluginConfiguration final Configuration config, @PluginElement("Filter") final Filter filter) {
             final List<AppenderRef> 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));
+            return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive,
+                    properties, config, includeLocation(includeLocation));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e017cbb/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
index 0f2536e..e4b63dc 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.CoreLoggerContexts;
 import org.apache.logging.log4j.core.config.AppenderRef;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -66,13 +67,14 @@ public class AsyncLoggerConfigTest {
     public void testIncludeLocationDefaultsToFalse() {
     	final LoggerConfig rootLoggerConfig = 
     			AsyncLoggerConfig.RootLogger.createLogger(
-    					null, "INFO", null, new AppenderRef[0], null, null, null);
+    					null, "INFO", null, new AppenderRef[0], null, new DefaultConfiguration(), null);
     	assertFalse("Include location should default to false for async logggers",
     			    rootLoggerConfig.isIncludeLocation());
     	
     	final LoggerConfig loggerConfig =
     	        AsyncLoggerConfig.createLogger(
-    	        		null, "INFO", "com.foo.Bar", null, new AppenderRef[0], null, null, null);
+    	        		null, "INFO", "com.foo.Bar", null, new AppenderRef[0], null, new DefaultConfiguration(),
+    	        		null);
     	assertFalse("Include location should default to false for async logggers",
     			    loggerConfig.isIncludeLocation());
     }