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 2013/10/16 09:16:54 UTC
svn commit: r1532659 - in /logging/log4j/log4j2/trunk:
log4j-core/src/main/java/org/apache/logging/log4j/core/appender/
log4j-core/src/main/java/org/apache/logging/log4j/core/async/
log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ src/changes/
Author: rpopma
Date: Wed Oct 16 07:16:54 2013
New Revision: 1532659
URL: http://svn.apache.org/r1532659
Log:
LOG4J2-423 Added MBeans for instrumenting AsyncAppenders and AsyncLogger RingBuffers, exposing queue size and remaining capacity
Added:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java (with props)
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java (with props)
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java (with props)
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java (with props)
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java
logging/log4j/log4j2/trunk/src/changes/changes.xml
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java Wed Oct 16 07:16:54 2013
@@ -53,6 +53,7 @@ public final class AsyncAppender extends
private static final String SHUTDOWN = "Shutdown";
private final BlockingQueue<Serializable> queue;
+ private final int queueSize;
private final boolean blocking;
private final Configuration config;
private final AppenderRef[] appenderRefs;
@@ -69,6 +70,7 @@ public final class AsyncAppender extends
final boolean includeLocation) {
super(name, filter, null, ignoreExceptions);
this.queue = new ArrayBlockingQueue<Serializable>(queueSize);
+ this.queueSize = queueSize;
this.blocking = blocking;
this.config = config;
this.appenderRefs = appenderRefs;
@@ -264,4 +266,52 @@ public final class AsyncAppender extends
}
}
}
+
+ /**
+ * Returns the names of the appenders that this asyncAppender delegates to
+ * as an array of Strings.
+ * @return the names of the sink appenders
+ */
+ public String[] getAppenderRefStrings() {
+ final String[] result = new String[appenderRefs.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = appenderRefs[i].getRef();
+ }
+ return result;
+ }
+
+ /**
+ * Returns {@code true} if this AsyncAppender will take a snapshot of the stack with
+ * every log event to determine the class and method where the logging call
+ * was made.
+ * @return {@code true} if location is included with every event, {@code false} otherwise
+ */
+ public boolean isIncludeLocation() {
+ return includeLocation;
+ }
+
+ /**
+ * Returns {@code true} if this AsyncAppender will block when the queue is full,
+ * or {@code false} if events are dropped when the queue is full.
+ * @return whether this AsyncAppender will block or drop events when the queue is full.
+ */
+ public boolean isBlocking() {
+ return blocking;
+ }
+
+ /**
+ * Returns the name of the appender that any errors are logged to or {@code null}.
+ * @return the name of the appender that any errors are logged to or {@code null}
+ */
+ public String getErrorRef() {
+ return errorRef;
+ }
+
+ public int getQueueCapacity() {
+ return queueSize;
+ }
+
+ public int getQueueRemainingCapacity() {
+ return queue.remainingCapacity();
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java Wed Oct 16 07:16:54 2013
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.core.con
import org.apache.logging.log4j.core.helpers.Clock;
import org.apache.logging.log4j.core.helpers.ClockFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.status.StatusLogger;
@@ -65,11 +66,12 @@ import com.lmax.disruptor.util.Util;
* at all.
* <p>
* For best performance, use AsyncLogger with the RandomAccessFileAppender or
- * RollingRandomAccessFileAppender, with immediateFlush=false. These appenders have
- * built-in support for the batching mechanism used by the Disruptor library,
- * 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.
+ * RollingRandomAccessFileAppender, with immediateFlush=false. These appenders
+ * have built-in support for the batching mechanism used by the Disruptor
+ * library, 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.
*/
public class AsyncLogger extends Logger {
private static final int HALF_A_SECOND = 500;
@@ -89,36 +91,32 @@ public class AsyncLogger extends Logger
final int ringBufferSize = calculateRingBufferSize();
final WaitStrategy waitStrategy = createWaitStrategy();
- disruptor = new Disruptor<RingBufferLogEvent>(
- RingBufferLogEvent.FACTORY, ringBufferSize, executor,
+ disruptor = new Disruptor<RingBufferLogEvent>(RingBufferLogEvent.FACTORY, ringBufferSize, executor,
ProducerType.MULTI, waitStrategy);
final EventHandler<RingBufferLogEvent>[] handlers = new RingBufferLogEventHandler[] {//
new RingBufferLogEventHandler() };
disruptor.handleExceptionsWith(getExceptionHandler());
disruptor.handleEventsWith(handlers);
- LOGGER.debug(
- "Starting AsyncLogger disruptor with ringbuffer size {}...",
- disruptor.getRingBuffer().getBufferSize());
+ LOGGER.debug("Starting AsyncLogger disruptor with ringbuffer size {}...", disruptor.getRingBuffer()
+ .getBufferSize());
disruptor.start();
}
private static int calculateRingBufferSize() {
int ringBufferSize = RINGBUFFER_DEFAULT_SIZE;
- final String userPreferredRBSize = System.getProperty(
- "AsyncLogger.RingBufferSize", String.valueOf(ringBufferSize));
+ final String userPreferredRBSize = System.getProperty("AsyncLogger.RingBufferSize",
+ 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);
+ 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);
+ LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", userPreferredRBSize, ringBufferSize);
}
return Util.ceilingNextPowerOfTwo(ringBufferSize);
}
@@ -148,16 +146,12 @@ public class AsyncLogger extends Logger
}
try {
@SuppressWarnings("unchecked")
- final
- Class<? extends ExceptionHandler> klass = (Class<? extends ExceptionHandler>) Class
- .forName(cls);
+ final Class<? extends ExceptionHandler> klass = (Class<? extends ExceptionHandler>) Class.forName(cls);
final ExceptionHandler result = klass.newInstance();
LOGGER.debug("AsyncLogger.ExceptionHandler=" + result);
return result;
} catch (final Exception ignored) {
- LOGGER.debug(
- "AsyncLogger.ExceptionHandler not set: error creating "
- + cls + ": ", ignored);
+ LOGGER.debug("AsyncLogger.ExceptionHandler not set: error creating " + cls + ": ", ignored);
return null;
}
}
@@ -165,13 +159,12 @@ public class AsyncLogger extends Logger
/**
* Constructs an {@code AsyncLogger} with the specified context, name and
* message factory.
- *
+ *
* @param context context of this logger
* @param name name of this logger
* @param messageFactory message factory of this logger
*/
- public AsyncLogger(final LoggerContext context, final String name,
- final MessageFactory messageFactory) {
+ public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory) {
super(context, name, messageFactory);
}
@@ -184,8 +177,7 @@ public class AsyncLogger extends Logger
}
@Override
- public void log(final Marker marker, final String fqcn, final Level level, final Message data,
- final Throwable t) {
+ public void log(final Marker marker, final String fqcn, final Level level, final Message data, final Throwable t) {
Info info = threadlocalInfo.get();
if (info == null) {
info = new Info();
@@ -195,8 +187,7 @@ public class AsyncLogger extends Logger
}
final boolean includeLocation = config.loggerConfig.isIncludeLocation();
- info.translator.setValues(this, getName(), marker, fqcn, level, data,
- t, //
+ info.translator.setValues(this, getName(), marker, fqcn, level, data, t, //
// config properties are taken care of in the EventHandler
// thread in the #actualAsyncLog method
@@ -230,13 +221,12 @@ public class AsyncLogger extends Logger
/**
* This method is called by the EventHandler that processes the
* RingBufferLogEvent in a separate thread.
- *
+ *
* @param event the event to log
*/
public void actualAsyncLog(final RingBufferLogEvent event) {
final Map<Property, Boolean> properties = config.loggerConfig.getProperties();
- event.mergePropertiesIntoContextMap(properties,
- config.config.getStrSubstitutor());
+ event.mergePropertiesIntoContextMap(properties, config.config.getStrSubstitutor());
config.logEvent(event);
}
@@ -264,4 +254,14 @@ public class AsyncLogger extends Logger
executor.shutdown(); // finally, kill the processor thread
threadlocalInfo = new ThreadLocal<Info>(); // LOG4J2-323
}
+
+ /**
+ * Creates and returns a new {@code RingBufferAdmin} that instruments the
+ * ringbuffer of the {@code AsyncLogger}.
+ *
+ * @param contextName name of the global {@code AsyncLoggerContext}
+ */
+ public static RingBufferAdmin createRingBufferAdmin(String contextName) {
+ return RingBufferAdmin.forAsyncLogger(disruptor.getRingBuffer(), contextName);
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java Wed Oct 16 07:16:54 2013
@@ -33,6 +33,7 @@ import org.apache.logging.log4j.core.con
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.helpers.Booleans;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
/**
* Asynchronous Logger object that is created via configuration and can be
@@ -131,6 +132,16 @@ public class AsyncLoggerConfig extends L
}
/**
+ * Creates and returns a new {@code RingBufferAdmin} that instruments the
+ * ringbuffer of this {@code AsyncLoggerConfig}.
+ *
+ * @param contextName name of the {@code LoggerContext}
+ */
+ public RingBufferAdmin createRingBufferAdmin(String contextName) {
+ return helper.createRingBufferAdmin(contextName, getName());
+ }
+
+ /**
* Factory method to create a LoggerConfig.
*
* @param additivity True if additive, false otherwise.
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java Wed Oct 16 07:16:54 2013
@@ -22,6 +22,7 @@ import java.util.concurrent.ThreadFactor
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
import org.apache.logging.log4j.status.StatusLogger;
import com.lmax.disruptor.BlockingWaitStrategy;
@@ -283,4 +284,15 @@ class AsyncLoggerConfigHelper {
disruptor.getRingBuffer().publishEvent(translator, event, asyncLoggerConfig);
}
+ /**
+ * Creates and returns a new {@code RingBufferAdmin} that instruments the
+ * ringbuffer of this {@code AsyncLoggerConfig}.
+ *
+ * @param contextName name of the {@code LoggerContext}
+ * @param loggerConfigName name of the logger config
+ */
+ public RingBufferAdmin createRingBufferAdmin(String contextName, String loggerConfigName) {
+ return RingBufferAdmin.forAsyncLoggerConfig(disruptor.getRingBuffer(), contextName, loggerConfigName);
+ }
+
}
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java Wed Oct 16 07:16:54 2013
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.jm
import javax.management.ObjectName;
import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.helpers.Assert;
/**
@@ -72,7 +73,7 @@ public class AppenderAdmin implements Ap
}
@Override
- public boolean isExceptionSuppressed() {
+ public boolean isIgnoreExceptions() {
return appender.ignoreExceptions();
}
@@ -80,4 +81,12 @@ public class AppenderAdmin implements Ap
public String getErrorHandler() {
return String.valueOf(appender.getHandler());
}
+
+ @Override
+ public String getFilter() {
+ if (appender instanceof AbstractFilterable) {
+ return String.valueOf(((AbstractFilterable) appender).getFilter());
+ }
+ return null;
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java Wed Oct 16 07:16:54 2013
@@ -71,7 +71,7 @@ public interface AppenderAdminMBean {
* @return {@code true} if any exceptions thrown by the Appender will be
* logged or {@code false} if such exceptions are re-thrown.
*/
- boolean isExceptionSuppressed();
+ boolean isIgnoreExceptions();
/**
* Returns the result of calling {@code toString} on the error handler of
@@ -81,4 +81,13 @@ public interface AppenderAdminMBean {
* appender, or {@code "null"}
*/
String getErrorHandler();
+
+ /**
+ * Returns a string description of all filters configured for the
+ * instrumented {@code Appender}.
+ *
+ * @return a string description of all configured filters for this
+ * appender
+ */
+ String getFilter();
}
Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java?rev=1532659&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java Wed Oct 16 07:16:54 2013
@@ -0,0 +1,133 @@
+/*
+ * 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.jmx;
+
+import javax.management.ObjectName;
+
+import org.apache.logging.log4j.core.appender.AsyncAppender;
+import org.apache.logging.log4j.core.helpers.Assert;
+
+/**
+ * Implementation of the {@code AsyncAppenderAdminMBean} interface.
+ */
+public class AsyncAppenderAdmin implements AsyncAppenderAdminMBean {
+
+ private final String contextName;
+ private final AsyncAppender asyncAppender;
+ private final ObjectName objectName;
+
+ /**
+ * Constructs a new {@code AsyncAppenderAdmin} with the specified contextName
+ * and async appender.
+ *
+ * @param contextName used in the {@code ObjectName} for this mbean
+ * @param appender the instrumented object
+ */
+ public AsyncAppenderAdmin(final String contextName, final AsyncAppender appender) {
+ // super(executor); // no notifications for now
+ this.contextName = Assert.isNotNull(contextName, "contextName");
+ this.asyncAppender = Assert.isNotNull(appender, "async appender");
+ try {
+ final String ctxName = Server.escape(this.contextName);
+ final String configName = Server.escape(appender.getName());
+ final String name = String.format(PATTERN, ctxName, configName);
+ objectName = new ObjectName(name);
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Returns the {@code ObjectName} of this mbean.
+ *
+ * @return the {@code ObjectName}
+ * @see AppenderAdminMBean#PATTERN
+ */
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ @Override
+ public String getName() {
+ return asyncAppender.getName();
+ }
+
+ @Override
+ public String getLayout() {
+ return String.valueOf(asyncAppender.getLayout());
+ }
+
+ @Override
+ public boolean isIgnoreExceptions() {
+ return asyncAppender.ignoreExceptions();
+ }
+
+ @Override
+ public String getErrorHandler() {
+ return String.valueOf(asyncAppender.getHandler());
+ }
+
+ @Override
+ public String getFilter() {
+ return String.valueOf(asyncAppender.getFilter());
+ }
+
+ @Override
+ public String[] getAppenderRefs() {
+ return asyncAppender.getAppenderRefStrings();
+ }
+
+ /**
+ * Returns {@code true} if this AsyncAppender will take a snapshot of the stack with
+ * every log event to determine the class and method where the logging call
+ * was made.
+ * @return {@code true} if location is included with every event, {@code false} otherwise
+ */
+ @Override
+ public boolean isIncludeLocation() {
+ return asyncAppender.isIncludeLocation();
+ }
+
+ /**
+ * Returns {@code true} if this AsyncAppender will block when the queue is full,
+ * or {@code false} if events are dropped when the queue is full.
+ * @return whether this AsyncAppender will block or drop events when the queue is full.
+ */
+ @Override
+ public boolean isBlocking() {
+ return asyncAppender.isBlocking();
+ }
+
+ /**
+ * Returns the name of the appender that any errors are logged to or {@code null}.
+ * @return the name of the appender that any errors are logged to or {@code null}
+ */
+ @Override
+ public String getErrorRef() {
+ return asyncAppender.getErrorRef();
+ }
+
+ @Override
+ public int getQueueCapacity() {
+ return asyncAppender.getQueueCapacity();
+ }
+
+ @Override
+ public int getQueueRemainingCapacity() {
+ return asyncAppender.getQueueRemainingCapacity();
+ }
+}
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java?rev=1532659&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java Wed Oct 16 07:16:54 2013
@@ -0,0 +1,131 @@
+/*
+ * 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.jmx;
+
+/**
+ * The MBean interface for monitoring and managing an {@code AsyncAppender}.
+ */
+public interface AsyncAppenderAdminMBean {
+ /**
+ * ObjectName pattern ({@value} ) for AsyncAppenderAdmin MBeans. This
+ * pattern contains two variables, where the first is the name of the
+ * context, the second is the name of the instrumented appender.
+ * <p>
+ * You can find all registered AsyncAppenderAdmin MBeans like this:
+ * </p>
+ *
+ * <pre>
+ * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ * String pattern = String.format(AsyncAppenderAdminMBean.PATTERN, "*", "*");
+ * Set<ObjectName> appenderNames = mbs.queryNames(new ObjectName(pattern), null);
+ * </pre>
+ * <p>
+ * Some characters are not allowed in ObjectNames. The logger context name
+ * and appender name may be quoted. When AsyncAppenderAdmin MBeans are
+ * registered, their ObjectNames are created using this pattern as follows:
+ * </p>
+ *
+ * <pre>
+ * String ctxName = Server.escape(loggerContext.getName());
+ * String appenderName = Server.escape(appender.getName());
+ * String name = String.format(PATTERN, ctxName, appenderName);
+ * ObjectName objectName = new ObjectName(name);
+ * </pre>
+ *
+ * @see Server#escape(String)
+ */
+ String PATTERN = "org.apache.logging.log4j2:type=LoggerContext,ctx=%s,sub=AsyncAppender,name=%s";
+
+ /**
+ * Returns the name of the instrumented {@code AsyncAppender}.
+ *
+ * @return the name of the AsyncAppender
+ */
+ String getName();
+
+ /**
+ * Returns the result of calling {@code toString} on the {@code Layout}
+ * object of the instrumented {@code AsyncAppender}.
+ *
+ * @return the {@code Layout} of the instrumented {@code AsyncAppender} as a
+ * string
+ */
+ String getLayout();
+
+ /**
+ * Returns how exceptions thrown on the instrumented {@code AsyncAppender}
+ * are handled.
+ *
+ * @return {@code true} if any exceptions thrown by the AsyncAppender will
+ * be logged or {@code false} if such exceptions are re-thrown.
+ */
+ boolean isIgnoreExceptions();
+
+ /**
+ * Returns the result of calling {@code toString} on the error handler of
+ * this appender, or {@code "null"} if no error handler was set.
+ *
+ * @return result of calling {@code toString} on the error handler of this
+ * appender, or {@code "null"}
+ */
+ String getErrorHandler();
+
+ /**
+ * Returns a string description of all filters configured for the
+ * instrumented {@code AsyncAppender}.
+ *
+ * @return a string description of all configured filters for this appender
+ */
+ String getFilter();
+
+ /**
+ * Returns a String array with the appender refs configured for the
+ * instrumented {@code AsyncAppender}.
+ *
+ * @return the appender refs for the instrumented {@code AsyncAppender}.
+ */
+ String[] getAppenderRefs();
+
+ /**
+ * Returns {@code true} if this AsyncAppender will take a snapshot of the
+ * stack with every log event to determine the class and method where the
+ * logging call was made.
+ *
+ * @return {@code true} if location is included with every event,
+ * {@code false} otherwise
+ */
+ boolean isIncludeLocation();
+
+ /**
+ * Returns {@code true} if this AsyncAppender will block when the queue is
+ * full, or {@code false} if events are dropped when the queue is full.
+ *
+ * @return whether this AsyncAppender will block or drop events when the
+ * queue is full.
+ */
+ boolean isBlocking();
+
+ /**
+ * Returns the name of the appender that any errors are logged to or {@code null}.
+ * @return the name of the appender that any errors are logged to or {@code null}
+ */
+ String getErrorRef();
+
+ int getQueueCapacity();
+
+ int getQueueRemainingCapacity();
+}
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java?rev=1532659&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java Wed Oct 16 07:16:54 2013
@@ -0,0 +1,75 @@
+/*
+ * 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.jmx;
+
+import javax.management.ObjectName;
+
+import org.apache.logging.log4j.core.helpers.Assert;
+
+import com.lmax.disruptor.RingBuffer;
+
+/**
+ * Instruments an LMAX Disruptor ring buffer.
+ */
+public class RingBufferAdmin implements RingBufferAdminMBean {
+
+ private final RingBuffer<?> ringBuffer;
+ private final ObjectName objectName;
+
+ public static RingBufferAdmin forAsyncLogger(RingBuffer<?> ringBuffer, String contextName) {
+ final String ctxName = Server.escape(contextName);
+ final String name = String.format(PATTERN_ASYNC_LOGGER, ctxName);
+ return new RingBufferAdmin(ringBuffer, name);
+ }
+
+ public static RingBufferAdmin forAsyncLoggerConfig(RingBuffer<?> ringBuffer,
+ String contextName, String configName) {
+ final String ctxName = Server.escape(contextName);
+ final String cfgName = Server.escape(configName);
+ final String name = String.format(PATTERN_ASYNC_LOGGER_CONFIG, ctxName, cfgName);
+ return new RingBufferAdmin(ringBuffer, name);
+ }
+
+ protected RingBufferAdmin(RingBuffer<?> ringBuffer, String mbeanName) {
+ this.ringBuffer = Assert.isNotNull(ringBuffer, "ringbuffer");
+ try {
+ objectName = new ObjectName(mbeanName);
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public long getBufferSize() {
+ return ringBuffer.getBufferSize();
+ }
+
+ public long getRemainingCapacity() {
+ return ringBuffer.remainingCapacity();
+ }
+
+ /**
+ * Returns the {@code ObjectName} of this mbean.
+ *
+ * @return the {@code ObjectName}
+ * @see RingBufferAdminMBean#PATTERN_ASYNC_LOGGER
+ * @see RingBufferAdminMBean#PATTERN_ASYNC_LOGGER_CONFIG
+ */
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+}
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java?rev=1532659&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java Wed Oct 16 07:16:54 2013
@@ -0,0 +1,71 @@
+/*
+ * 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.jmx;
+
+/**
+ * The MBean interface for monitoring and managing an LMAX Disruptor ring
+ * buffer.
+ */
+public interface RingBufferAdminMBean {
+ /**
+ * ObjectName pattern ({@value}) for the RingBufferAdmin MBean that instruments
+ * the global {@code AsyncLogger} ring buffer.
+ * This pattern contains one variable: the name of the context.
+ * <p>
+ * You can find the registered RingBufferAdmin MBean for the global AsyncLogger like this:
+ * </p>
+ * <pre>
+ * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ * String pattern = String.format(RingBufferAdminMBean.PATTERN_ASYNC_LOGGER, "*");
+ * Set<ObjectName> asyncLoggerNames = mbs.queryNames(new ObjectName(pattern), null);
+ * </pre>
+ */
+ String PATTERN_ASYNC_LOGGER = "org.apache.logging.log4j2:type=LoggerContext,ctx=%s,name=AsyncLoggerRingBuffer";
+
+ /**
+ * ObjectName pattern ({@value}) for RingBufferAdmin MBeans that instrument
+ * {@code AsyncLoggerConfig} ring buffers.
+ * This pattern contains three variables, where the first is the name of the
+ * context, the second and third are identical and the name of the instrumented logger config.
+ * <p>
+ * You can find all registered RingBufferAdmin MBeans like this:
+ * </p>
+ * <pre>
+ * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ * String pattern = String.format(RingBufferAdminMBean.PATTERN_ASYNC_LOGGER_CONFIG, "*", "*");
+ * Set<ObjectName> asyncConfigNames = mbs.queryNames(new ObjectName(pattern), null);
+ * </pre>
+ */
+ String PATTERN_ASYNC_LOGGER_CONFIG = "org.apache.logging.log4j2:type=LoggerContext,ctx=%s,sub=LoggerConfig,name=%s,subtype=RingBuffer";
+
+ /**
+ * Returns the number of slots that the ring buffer was configured with.
+ * Disruptor ring buffers are bounded-size data structures, this number does
+ * not change during the life of the ring buffer.
+ *
+ * @return the number of slots that the ring buffer was configured with
+ */
+ long getBufferSize();
+
+ /**
+ * Returns the number of available slots in the ring buffer. May vary wildly
+ * between invocations.
+ *
+ * @return the number of available slots in the ring buffer
+ */
+ long getRemainingCapacity();
+}
Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java Wed Oct 16 07:16:54 2013
@@ -34,6 +34,10 @@ import javax.management.ObjectName;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AsyncAppender;
+import org.apache.logging.log4j.core.async.AsyncLogger;
+import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
+import org.apache.logging.log4j.core.async.AsyncLoggerContext;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.status.StatusLogger;
@@ -147,7 +151,9 @@ public final class Server {
// first unregister the MBeans that instrument the
// previous instrumented LoggerConfigs and Appenders
unregisterLoggerConfigs(context.getName(), mbs);
+ unregisterAsyncLoggerConfigRingBufferAdmins(context.getName(), mbs);
unregisterAppenders(context.getName(), mbs);
+ unregisterAsyncAppenders(context.getName(), mbs);
// now provide instrumentation for the newly configured
// LoggerConfigs and Appenders
@@ -189,9 +195,12 @@ public final class Server {
public static void unregisterContext(String contextName, MBeanServer mbs) {
final String pattern = LoggerContextAdminMBean.PATTERN;
final String search = String.format(pattern, contextName, "*");
- unregisterAllMatching(search, mbs);
+ unregisterAllMatching(search, mbs); // unregister context mbean
unregisterLoggerConfigs(contextName, mbs);
unregisterAppenders(contextName, mbs);
+ unregisterAsyncAppenders(contextName, mbs);
+ unregisterAsyncLoggerRingBufferAdmins(contextName, mbs);
+ unregisterAsyncLoggerConfigRingBufferAdmins(contextName, mbs);
}
private static void registerStatusLogger(final MBeanServer mbs, final Executor executor)
@@ -209,13 +218,26 @@ public final class Server {
mbs.registerMBean(mbean, mbean.getObjectName());
}
+ /**
+ * Registers MBeans for all contexts in the list.
+ * First unregisters each context (and nested loggers, appender etc)
+ * to prevent InstanceAlreadyExistsExceptions.
+ */
private static void registerContexts(final List<LoggerContext> contexts, final MBeanServer mbs,
final Executor executor) throws InstanceAlreadyExistsException, MBeanRegistrationException,
NotCompliantMBeanException {
for (final LoggerContext ctx : contexts) {
+ // first unregister the context and all nested loggers & appenders
+ unregisterContext(ctx.getName());
+
final LoggerContextAdmin mbean = new LoggerContextAdmin(ctx, executor);
mbs.registerMBean(mbean, mbean.getObjectName());
+
+ if (ctx instanceof AsyncLoggerContext) {
+ RingBufferAdmin rbmbean = AsyncLogger.createRingBufferAdmin(ctx.getName());
+ mbs.registerMBean(rbmbean, rbmbean.getObjectName());
+ }
}
}
@@ -233,6 +255,27 @@ public final class Server {
unregisterAllMatching(search, mbs);
}
+ private static void unregisterAsyncAppenders(final String contextName,
+ final MBeanServer mbs) {
+ final String pattern = AsyncAppenderAdminMBean.PATTERN;
+ final String search = String.format(pattern, contextName, "*");
+ unregisterAllMatching(search, mbs);
+ }
+
+ private static void unregisterAsyncLoggerRingBufferAdmins(final String contextName,
+ final MBeanServer mbs) {
+ final String pattern1 = RingBufferAdminMBean.PATTERN_ASYNC_LOGGER;
+ final String search1 = String.format(pattern1, contextName);
+ unregisterAllMatching(search1, mbs);
+ }
+
+ private static void unregisterAsyncLoggerConfigRingBufferAdmins(final String contextName,
+ final MBeanServer mbs) {
+ final String pattern2 = RingBufferAdminMBean.PATTERN_ASYNC_LOGGER_CONFIG;
+ final String search2 = String.format(pattern2, contextName, "*");
+ unregisterAllMatching(search2, mbs);
+ }
+
private static void unregisterAllMatching(final String search, final MBeanServer mbs) {
try {
final ObjectName pattern = new ObjectName(search);
@@ -254,6 +297,12 @@ public final class Server {
final LoggerConfig cfg = map.get(name);
final LoggerConfigAdmin mbean = new LoggerConfigAdmin(ctx.getName(), cfg);
mbs.registerMBean(mbean, mbean.getObjectName());
+
+ if (cfg instanceof AsyncLoggerConfig) {
+ AsyncLoggerConfig async = (AsyncLoggerConfig) cfg;
+ RingBufferAdmin rbmbean = async.createRingBufferAdmin(ctx.getName());
+ mbs.registerMBean(rbmbean, rbmbean.getObjectName());
+ }
}
}
@@ -263,8 +312,15 @@ public final class Server {
final Map<String, Appender> map = ctx.getConfiguration().getAppenders();
for (final String name : map.keySet()) {
final Appender appender = map.get(name);
- final AppenderAdmin mbean = new AppenderAdmin(ctx.getName(), appender);
- mbs.registerMBean(mbean, mbean.getObjectName());
+
+ if (appender instanceof AsyncAppender) {
+ AsyncAppender async = ((AsyncAppender) appender);
+ final AsyncAppenderAdmin mbean = new AsyncAppenderAdmin(ctx.getName(), async);
+ mbs.registerMBean(mbean, mbean.getObjectName());
+ } else {
+ final AppenderAdmin mbean = new AppenderAdmin(ctx.getName(), appender);
+ mbs.registerMBean(mbean, mbean.getObjectName());
+ }
}
}
}
Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1532659&r1=1532658&r2=1532659&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Wed Oct 16 07:16:54 2013
@@ -21,6 +21,10 @@
</properties>
<body>
<release version="2.0RC1" date="2013-MM-DD" description="Bug fixes and enhancements">
+ <action issue="LOG4J2-423" dev="rpopma" type="add">
+ Added MBeans for instrumenting AsyncAppenders and AsyncLogger RingBuffers,
+ exposing queue size, remaining capacity and other attributes.
+ </action>
<action issue="LOG4J2-323" dev="rpopma" type="fix">
Resolved memory leak by releasing reference to ThreadLocal when
AsyncLogger is stopped.