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 af93e2615e5..4b28ed58f08 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,13 +25,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.TimeUnit; +import java.util.function.LongSupplier; 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.Log4jPropertyKey; -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; @@ -157,11 +157,14 @@ private static void runTest( final Logger log = context.getLogger("com.foo.Bar"); final String loggerContextName = context.getClass().getSimpleName(); - RingBufferAdmin ring; + final LongSupplier remainingCapacity; if (context instanceof AsyncLoggerContext) { - ring = ((AsyncLoggerContext) context).createRingBufferAdmin(); + remainingCapacity = + ((AsyncLoggerContext) context).getAsyncLoggerDisruptor().getRingBuffer()::remainingCapacity; } else { - ring = ((AsyncLoggerConfig) log.get()).createRingBufferAdmin(""); + remainingCapacity = + ((AsyncLoggerConfigDisruptor) ((AsyncLoggerConfig) log.get()).getAsyncLoggerConfigDelegate()) + .getRingBuffer()::remainingCapacity; } for (int i = 0; i < LINE_COUNT; i++) { @@ -169,7 +172,7 @@ private static void runTest( if (i >= 128) { waitAtMost(500, TimeUnit.MILLISECONDS) .pollDelay(10, TimeUnit.MILLISECONDS) - .until(() -> ring.getRemainingCapacity() > 0); + .until(() -> remainingCapacity.getAsLong() > 0); } if ((i & 1) == 1) { ThreadContext.put("count", String.valueOf(i)); 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 6b1f3a1464e..54da28a5db2 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 @@ -19,12 +19,13 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; -import com.lmax.disruptor.dsl.Disruptor; +import com.lmax.disruptor.RingBuffer; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Stack; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; @@ -36,7 +37,6 @@ import org.apache.logging.log4j.core.appender.AsyncAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.jmx.RingBufferAdmin; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.status.StatusData; import org.apache.logging.log4j.status.StatusLogger; @@ -234,29 +234,19 @@ static List getMessages(final List logEvents) { } static long asyncRemainingCapacity(final Logger logger) { - if (logger instanceof AsyncLogger) { - try { - final Field f = field(AsyncLogger.class, "loggerDisruptor"); - return ((AsyncLoggerDisruptor) f.get(logger)) - .getDisruptor() - .getRingBuffer() - .remainingCapacity(); - } catch (final Exception ex) { - throw new RuntimeException(ex); - } + if (logger instanceof AsyncLogger asyncLogger) { + return Optional.ofNullable(asyncLogger.getAsyncLoggerDisruptor()) + .map(AsyncLoggerDisruptor::getRingBuffer) + .map(RingBuffer::remainingCapacity) + .orElse(0L); } else { final LoggerConfig loggerConfig = ((org.apache.logging.log4j.core.Logger) logger).get(); - if (loggerConfig instanceof AsyncLoggerConfig) { - try { - final Object delegate = - field(AsyncLoggerConfig.class, "delegate").get(loggerConfig); - return ((Disruptor) field(AsyncLoggerConfigDisruptor.class, "disruptor") - .get(delegate)) - .getRingBuffer() - .remainingCapacity(); - } catch (final Exception ex) { - throw new RuntimeException(ex); - } + if (loggerConfig instanceof AsyncLoggerConfig asyncLoggerConfig) { + return Optional.ofNullable( + (AsyncLoggerConfigDisruptor) asyncLoggerConfig.getAsyncLoggerConfigDelegate()) + .map(AsyncLoggerConfigDisruptor::getRingBuffer) + .map(RingBuffer::remainingCapacity) + .orElse(0L); } else { final Appender async = loggerConfig.getAppenders().get("async"); if (async instanceof AsyncAppender) { @@ -287,26 +277,25 @@ protected static void assertAsyncAppender(final LoggerContext ctx) { protected static void assertAsyncLogger(final LoggerContext ctx, final int expectedBufferSize) { assertThat(ctx).isInstanceOf(AsyncLoggerContext.class); - final RingBufferAdmin ringBufferAdmin = ((AsyncLoggerContext) ctx).createRingBufferAdmin(); - assertThat(ringBufferAdmin.getRemainingCapacity()).isEqualTo(expectedBufferSize); + assertThat(((AsyncLoggerContext) ctx) + .getAsyncLoggerDisruptor() + .getRingBuffer() + .getBufferSize()) + .isEqualTo(expectedBufferSize); final Configuration config = ctx.getConfiguration(); assertThat(config).isNotNull(); assertThat(config.getRootLogger()).isNotInstanceOf(AsyncLoggerConfig.class); } - protected static void assertAsyncLoggerConfig(final LoggerContext ctx, final int expectedBufferSize) - throws ReflectiveOperationException { + protected static void assertAsyncLoggerConfig(final LoggerContext ctx, final int expectedBufferSize) { assertThat(ctx).isNotInstanceOf(AsyncLoggerContext.class); final Configuration config = ctx.getConfiguration(); assertThat(config).isNotNull(); assertThat(config.getRootLogger()).isInstanceOf(AsyncLoggerConfig.class); - final AsyncLoggerConfigDisruptor disruptorWrapper = - (AsyncLoggerConfigDisruptor) config.getAsyncLoggerConfigDelegate(); - final Disruptor disruptor = (Disruptor) - field(AsyncLoggerConfigDisruptor.class, "disruptor").get(disruptorWrapper); - assertThat(disruptor.getBufferSize()).isEqualTo(expectedBufferSize); + final AsyncLoggerConfigDisruptor disruptor = (AsyncLoggerConfigDisruptor) config.getAsyncLoggerConfigDelegate(); + assertThat(disruptor.getRingBuffer().getBufferSize()).isEqualTo(expectedBufferSize); } protected static void assertFormatMessagesInBackground() { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/jmx/ServerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/jmx/ServerTest.java deleted file mode 100644 index 958785dee8a..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/jmx/ServerTest.java +++ /dev/null @@ -1,118 +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.jmx; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import javax.management.ObjectName; -import org.junit.jupiter.api.Test; - -/** - * Unit tests for the Server class. - */ -public class ServerTest { - - @Test - public void testEscapeQuotesButDoesNotEscapeEquals() throws Exception { - final String ctx = "WebAppClassLoader=1320771902@4eb9613e"; // LOG4J2-492 - final String ctxName = Server.escape(ctx); - assertEquals("\"WebAppClassLoader=1320771902@4eb9613e\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesButDoesNotEscapeComma() throws Exception { - final String ctx = "a,b,c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a,b,c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesButDoesNotEscapeColon() throws Exception { - final String ctx = "a:b:c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a:b:c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesAndEscapesQuestion() throws Exception { - final String ctx = "a?c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a\\?c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesAndEscapesStar() throws Exception { - final String ctx = "a*c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a\\*c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesAndEscapesBackslash() throws Exception { - final String ctx = "a\\c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a\\\\c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeQuotesAndEscapesQuote() throws Exception { - final String ctx = "a\"c"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a\\\"c\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeIgnoresSpaces() throws Exception { - final String ctx = "a c"; - final String ctxName = Server.escape(ctx); - assertEquals("a c", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeEscapesLineFeed() throws Exception { - final String ctx = "a\rc"; - final String ctxName = Server.escape(ctx); - assertEquals("ac", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } - - @Test - public void testEscapeEscapesCarriageReturn() throws Exception { - final String ctx = "a\nc"; - final String ctxName = Server.escape(ctx); - assertEquals("\"a\\nc\"", ctxName); - new ObjectName(String.format(LoggerContextAdminMBean.PATTERN, ctxName)); - // no MalformedObjectNameException = success - } -} 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 2a17fd76b51..9a2decdd0f7 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 @@ -42,7 +42,6 @@ import org.apache.logging.log4j.core.config.NullConfiguration; import org.apache.logging.log4j.core.config.Reconfigurable; import org.apache.logging.log4j.core.impl.Log4jPropertyKey; -import org.apache.logging.log4j.core.jmx.Server; import org.apache.logging.log4j.core.util.Cancellable; import org.apache.logging.log4j.core.util.ExecutorServices; import org.apache.logging.log4j.core.util.NetUtils; @@ -436,13 +435,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) { } this.setStopping(); - String name = getName(); - try { - Server.unregisterLoggerContext(name); // LOG4J2-406, LOG4J2-500 - } catch (final LinkageError | Exception e) { - // LOG4J2-1506 Hello Android, GAE - LOGGER.error("Unable to unregister MBeans", e); - } + if (shutdownCallback != null) { shutdownCallback.cancel(); shutdownCallback = null; @@ -736,13 +729,6 @@ public Configuration setConfiguration(final Configuration config) { notifyConfigurationStopped(prev); } - try { - Server.reregisterMBeansAfterReconfigure(); - } catch (final LinkageError | Exception e) { - // LOG4J2-716: Android has no java.lang.management - LOGGER.error("Could not reconfigure JMX", e); - } - return prev; } finally { configLock.unlock(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java index 094a1482933..73920e0cd8c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java @@ -27,7 +27,6 @@ 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.core.jmx.RingBufferAdmin; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginFactory; @@ -210,17 +209,6 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) { return true; } - /** - * Creates and returns a new {@code RingBufferAdmin} that instruments the - * ringbuffer of this {@code AsyncLoggerConfig}. - * - * @param contextName name of the {@code LoggerContext} - * @return a new {@code RingBufferAdmin} that instruments the ringbuffer - */ - public RingBufferAdmin createRingBufferAdmin(final String contextName) { - return delegate.createRingBufferAdmin(contextName, getName()); - } - // Note: for asynchronous loggers, includeLocation default is FALSE protected static boolean includeLocation(final String includeLocationConfigValue) { return Boolean.parseBoolean(includeLocationConfigValue); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java index b68e39b10a0..e2145a93f49 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java @@ -19,7 +19,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.LogEventFactory; -import org.apache.logging.log4j.core.jmx.RingBufferAdmin; /** * Encapsulates the mechanism used to log asynchronously. There is one delegate per configuration, which is shared by @@ -27,16 +26,6 @@ */ public interface AsyncLoggerConfigDelegate { - /** - * 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 - * @return the RingBufferAdmin that instruments the ringbuffer - */ - RingBufferAdmin createRingBufferAdmin(final String contextName, final String loggerConfigName); - /** * Returns the {@code EventRoute} for the event with the specified level. * 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 b9e1721bbc6..3f27efc83fb 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 @@ -39,7 +39,6 @@ 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; @@ -424,14 +423,8 @@ private LogEvent ensureImmutable(final LogEvent event) { return result; } - /* - * (non-Javadoc) - * - * @see org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate#createRingBufferAdmin(java.lang.String, - * java.lang.String) - */ - @Override - public RingBufferAdmin createRingBufferAdmin(final String contextName, final String loggerConfigName) { - return RingBufferAdmin.forAsyncLoggerConfig(disruptor.getRingBuffer(), contextName, loggerConfigName); + // package-protected for tests + RingBuffer getRingBuffer() { + return disruptor.getRingBuffer(); } } 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 9f6389081d4..0125c4e86ee 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 @@ -22,7 +22,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.jmx.RingBufferAdmin; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory; import org.apache.logging.log4j.status.StatusLogger; @@ -131,13 +130,8 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) { return true; } - /** - * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of the {@code AsyncLogger} - * objects in this {@code LoggerContext}. - * - * @return a new {@code RingBufferAdmin} that instruments the ringbuffer - */ - public RingBufferAdmin createRingBufferAdmin() { - return loggerDisruptor.createRingBufferAdmin(getName()); + // package-protected for tests + AsyncLoggerDisruptor getAsyncLoggerDisruptor() { + return loggerDisruptor; } } 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 2edf4bb9bb2..b3281e42168 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 @@ -31,7 +31,6 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.AbstractLifeCycle; import org.apache.logging.log4j.core.impl.Log4jPropertyKey; -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; @@ -78,10 +77,6 @@ public void setContextName(final String name) { contextName = name; } - Disruptor getDisruptor() { - return disruptor; - } - /** * Creates and starts a new Disruptor and associated thread if none currently exists. * @@ -150,7 +145,7 @@ public Thread newThread(final Runnable r) { */ @Override public boolean stop(final long timeout, final TimeUnit timeUnit) { - final Disruptor temp = getDisruptor(); + final Disruptor temp = this.disruptor; if (temp == null) { LOGGER.trace("[{}] AsyncLoggerDisruptor: disruptor for this context already shut down.", contextName); return true; // disruptor was already shut down by another thread @@ -198,17 +193,6 @@ private static boolean hasBacklog(final Disruptor theDisruptor) { return !ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize()); } - /** - * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of the {@code AsyncLogger}. - * - * @param jmxContextName name of the {@code AsyncLoggerContext} - * @return a new {@code RingBufferAdmin} that instruments the ringbuffer - */ - public RingBufferAdmin createRingBufferAdmin(final String jmxContextName) { - final RingBuffer ring = disruptor == null ? null : disruptor.getRingBuffer(); - return RingBufferAdmin.forAsyncLogger(ring, jmxContextName); - } - EventRoute getEventRoute(final Level logLevel) { final int remainingCapacity = remainingDisruptorCapacity(); if (remainingCapacity < 0) { @@ -295,4 +279,9 @@ private void logWarningOnNpeFromDisruptorPublish( msg.getFormattedMessage(), thrown == null ? "" : Throwables.toStringList(thrown)); } + + // package-protected for tests + RingBuffer getRingBuffer() { + return disruptor.getRingBuffer(); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java deleted file mode 100644 index 2e5184615a4..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java +++ /dev/null @@ -1,91 +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.jmx; - -import java.util.Objects; -import javax.management.ObjectName; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.filter.AbstractFilterable; - -/** - * Implementation of the {@code AppenderAdminMBean} interface. - */ -public class AppenderAdmin implements AppenderAdminMBean { - - private final String contextName; - private final Appender appender; - private final ObjectName objectName; - - /** - * Constructs a new {@code AppenderAdmin} with the specified contextName - * and appender. - * - * @param contextName used in the {@code ObjectName} for this mbean - * @param appender the instrumented object - */ - public AppenderAdmin(final String contextName, final Appender appender) { - // super(executor); // no notifications for now - this.contextName = Objects.requireNonNull(contextName, "contextName"); - this.appender = Objects.requireNonNull(appender, "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 appender.getName(); - } - - @Override - public String getLayout() { - return String.valueOf(appender.getLayout()); - } - - @Override - public boolean isIgnoreExceptions() { - return appender.ignoreExceptions(); - } - - @Override - public String getErrorHandler() { - return String.valueOf(appender.getHandler()); - } - - @Override - public String getFilter() { - if (appender instanceof AbstractFilterable) { - return String.valueOf(((AbstractFilterable) appender).getFilter()); - } - return null; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java deleted file mode 100644 index d488ceaf988..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdminMBean.java +++ /dev/null @@ -1,92 +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.jmx; - -/** - * The MBean interface for monitoring and managing an {@code Appender}. - */ -public interface AppenderAdminMBean { - /** - * ObjectName pattern ({@value}) for AppenderAdmin MBeans. - * This pattern contains two variables, where the first is the - * name of the context, the second is the name of the instrumented appender. - *

- * You can find all registered AppenderAdmin MBeans like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(AppenderAdminMBean.PATTERN, "*", "*");
-     * Set<ObjectName> appenderNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * Some characters are not allowed in ObjectNames. The logger context name - * and appender name may be quoted. When AppenderAdmin MBeans are - * registered, their ObjectNames are created using this pattern as follows: - *

- *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String appenderName = Server.escape(appender.getName());
-     * String name = String.format(PATTERN, ctxName, appenderName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s,component=Appenders,name=%s"; - - /** - * Returns the name of the instrumented {@code Appender}. - * - * @return the name of the Appender - */ - String getName(); - - /** - * Returns the result of calling {@code toString} on the {@code Layout} - * object of the instrumented {@code Appender}. - * - * @return the {@code Layout} of the instrumented {@code Appender} as a - * string - */ - String getLayout(); - - /** - * Returns how exceptions thrown on the instrumented {@code Appender} are - * handled. - * - * @return {@code true} if any exceptions thrown by the Appender 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 Appender}. - * - * @return a string description of all configured filters for this - * appender - */ - String getFilter(); -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java deleted file mode 100644 index eee0506cd88..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java +++ /dev/null @@ -1,132 +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.jmx; - -import java.util.Objects; -import javax.management.ObjectName; -import org.apache.logging.log4j.core.appender.AsyncAppender; - -/** - * 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 = Objects.requireNonNull(contextName, "contextName"); - this.asyncAppender = Objects.requireNonNull(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(); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java deleted file mode 100644 index 89198f74384..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdminMBean.java +++ /dev/null @@ -1,131 +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.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. - *

- * You can find all registered AsyncAppenderAdmin MBeans like this: - *

- * - *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(AsyncAppenderAdminMBean.PATTERN, "*", "*");
-     * Set<ObjectName> appenderNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * 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: - *

- * - *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String appenderName = Server.escape(appender.getName());
-     * String name = String.format(PATTERN, ctxName, appenderName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * - * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s,component=AsyncAppenders,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(); -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java deleted file mode 100644 index ddcc62dd14f..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java +++ /dev/null @@ -1,68 +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.jmx; - -import java.util.Objects; -import javax.management.ObjectName; -import org.apache.logging.log4j.core.selector.ContextSelector; - -/** - * Implementation of the {@code ContextSelectorAdminMBean} interface. - */ -public class ContextSelectorAdmin implements ContextSelectorAdminMBean { - - private final ObjectName objectName; - private final ContextSelector selector; - - /** - * Constructs a new {@code ContextSelectorAdmin}. - * - * @param contextName name of the LoggerContext under which to register this - * ContextSelectorAdmin. Note that the ContextSelector may be - * registered multiple times, once for each LoggerContext. In web - * containers, each web application has its own LoggerContext and - * by associating the ContextSelector with the LoggerContext, all - * associated MBeans can be unloaded when the web application is - * undeployed. - * @param selector the instrumented object - */ - public ContextSelectorAdmin(final String contextName, final ContextSelector selector) { - super(); - this.selector = Objects.requireNonNull(selector, "ContextSelector"); - try { - final String mbeanName = String.format(PATTERN, Server.escape(contextName)); - objectName = new ObjectName(mbeanName); - } catch (final Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * Returns the {@code ObjectName} of this mbean. - * - * @return the {@code ObjectName} - * @see ContextSelectorAdminMBean#PATTERN - */ - public ObjectName getObjectName() { - return objectName; - } - - @Override - public String getImplementationClassName() { - return selector.getClass().getName(); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdminMBean.java deleted file mode 100644 index 564944f0294..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdminMBean.java +++ /dev/null @@ -1,55 +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.jmx; - -/** - * The MBean interface for monitoring and managing the {@code ContextSelector}. - */ -public interface ContextSelectorAdminMBean { - /** - * ObjectName pattern ({@value}) for ContextSelectorAdmin MBeans. - * This pattern contains a variable, which is the name of the logger context. - *

- * You can find all registered ContextSelectorAdmin MBeans like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(ContextSelectorAdminMBean.PATTERN, "*");
-     * Set<ObjectName> contextSelectorNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * Some characters are not allowed in ObjectNames. The logger context name - * may be quoted. When ContextSelectorAdmin MBeans are - * registered, their ObjectNames are created using this pattern as follows: - *

- *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String name = String.format(PATTERN, ctxName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s,component=ContextSelector"; - - /** - * Returns the name of the class implementing the {@code ContextSelector} - * interface. - * - * @return the name of the {@code ContextSelector} implementation class. - */ - String getImplementationClassName(); -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java deleted file mode 100644 index 09e7fec94ad..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java +++ /dev/null @@ -1,113 +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.jmx; - -import java.util.List; -import java.util.Objects; -import javax.management.ObjectName; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.AppenderRef; -import org.apache.logging.log4j.core.config.LoggerConfig; - -/** - * Implementation of the {@code LoggerConfigAdminMBean} interface. - */ -public class LoggerConfigAdmin implements LoggerConfigAdminMBean { - - private final LoggerContext loggerContext; - private final LoggerConfig loggerConfig; - private final ObjectName objectName; - - /** - * Constructs a new {@code LoggerConfigAdmin} with the specified LoggerContext - * and logger config. - * - * @param loggerContext used in the {@code ObjectName} for this mbean - * @param loggerConfig the instrumented object - */ - public LoggerConfigAdmin(final LoggerContext loggerContext, final LoggerConfig loggerConfig) { - // super(executor); // no notifications for now - this.loggerContext = Objects.requireNonNull(loggerContext, "loggerContext"); - this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig"); - try { - final String ctxName = Server.escape(loggerContext.getName()); - final String configName = Server.escape(loggerConfig.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 LoggerConfigAdminMBean#PATTERN - */ - public ObjectName getObjectName() { - return objectName; - } - - @Override - public String getName() { - return loggerConfig.getName(); - } - - @Override - public String getLevel() { - return loggerConfig.getLevel().name(); - } - - @Override - public void setLevel(final String level) { - loggerConfig.setLevel(Level.getLevel(level)); - loggerContext.updateLoggers(); - } - - @Override - public boolean isAdditive() { - return loggerConfig.isAdditive(); - } - - @Override - public void setAdditive(final boolean additive) { - loggerConfig.setAdditive(additive); - loggerContext.updateLoggers(); - } - - @Override - public boolean isIncludeLocation() { - return loggerConfig.isIncludeLocation(); - } - - @Override - public String getFilter() { - return String.valueOf(loggerConfig.getFilter()); - } - - @Override - public String[] getAppenderRefs() { - final List refs = loggerConfig.getAppenderRefs(); - final String[] result = new String[refs.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = refs.get(i).getRef(); - } - return result; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdminMBean.java deleted file mode 100644 index d1904fd66b1..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdminMBean.java +++ /dev/null @@ -1,114 +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.jmx; - -/** - * The MBean interface for monitoring and managing a {@code LoggerConfig}. - */ -public interface LoggerConfigAdminMBean { - /** - * ObjectName pattern ({@value}) for LoggerConfigAdmin MBeans. - * This pattern contains two variables, where the first is the name of the - * context, the second is the name of the instrumented logger config. - *

- * You can find all registered LoggerConfigAdmin MBeans like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(LoggerConfigAdminMBean.PATTERN, "*", "*");
-     * Set<ObjectName> loggerConfigNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * Some characters are not allowed in ObjectNames. The logger context name - * and logger config name may be quoted. When LoggerConfigAdmin MBeans are - * registered, their ObjectNames are created using this pattern as follows: - *

- *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String loggerConfigName = Server.escape(loggerConfig.getName());
-     * String name = String.format(PATTERN, ctxName, loggerConfigName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s,component=Loggers,name=%s"; - - /** - * Returns the name of the instrumented {@code LoggerConfig}. - * - * @return the name of the LoggerConfig - */ - String getName(); - - /** - * Returns the {@code LoggerConfig} level as a String. - * - * @return the {@code LoggerConfig} level. - */ - String getLevel(); - - /** - * Sets the {@code LoggerConfig} level to the specified value. - * - * @param level the new {@code LoggerConfig} level. - * @throws IllegalArgumentException if the specified level is not one of - * "OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", - * "ALL" - */ - void setLevel(String level); - - /** - * Returns whether the instrumented {@code LoggerConfig} is additive. - * - * @return {@code true} if the LoggerConfig is additive, {@code false} - * otherwise - */ - boolean isAdditive(); - - /** - * Sets whether the instrumented {@code LoggerConfig} should be additive. - * - * @param additive {@code true} if the instrumented LoggerConfig should be - * additive, {@code false} otherwise - */ - void setAdditive(boolean additive); - - /** - * Returns whether the instrumented {@code LoggerConfig} is configured to - * include location. - * - * @return whether location should be passed downstream - */ - boolean isIncludeLocation(); - - /** - * Returns a string description of all filters configured for the - * instrumented {@code LoggerConfig}. - * - * @return a string description of all configured filters for this - * LoggerConfig - */ - String getFilter(); - - /** - * Returns a String array with the appender refs configured for the - * instrumented {@code LoggerConfig}. - * - * @return the appender refs for the instrumented {@code LoggerConfig}. - */ - String[] getAppenderRefs(); -} 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 deleted file mode 100644 index 36b2f9a3b41..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java +++ /dev/null @@ -1,241 +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.jmx; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Map; -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.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. - */ -public class LoggerContextAdmin extends NotificationBroadcasterSupport implements LoggerContextAdminMBean { - private static final int PAGE = 4 * 1024; - private static final int TEXT_BUFFER = 64 * 1024; - private static final int BUFFER_SIZE = 2048; - private static final StatusLogger LOGGER = StatusLogger.getLogger(); - - private final AtomicLong sequenceNo = new AtomicLong(); - private final ObjectName objectName; - private final LoggerContext loggerContext; - - /** - * Constructs a new {@code LoggerContextAdmin} with the {@code Executor} to be used for sending {@code Notification} - * s asynchronously to listeners. - * - * @param executor used to send notifications asynchronously - * @param loggerContext the instrumented object - */ - public LoggerContextAdmin(final LoggerContext loggerContext, final Executor executor) { - super(executor, createNotificationInfo()); - this.loggerContext = Objects.requireNonNull(loggerContext, "loggerContext"); - try { - final String ctxName = Server.escape(loggerContext.getName()); - final String name = String.format(PATTERN, ctxName); - objectName = new ObjectName(name); - } catch (final Exception e) { - throw new IllegalStateException(e); - } - loggerContext.addConfigurationStartedListener(ignored -> sendReconfiguredNotification()); - } - - private static MBeanNotificationInfo createNotificationInfo() { - final String[] notifTypes = new String[] {NOTIF_TYPE_RECONFIGURED}; - final String name = Notification.class.getName(); - final String description = "Configuration reconfigured"; - return new MBeanNotificationInfo(notifTypes, name, description); - } - - private void sendReconfiguredNotification() { - final var notification = new Notification(NOTIF_TYPE_RECONFIGURED, objectName, sequenceNo.getAndIncrement()); - sendNotification(notification); - } - - @Override - public String getStatus() { - return loggerContext.getState().toString(); - } - - @Override - public String getName() { - return loggerContext.getName(); - } - - private Configuration getConfig() { - return loggerContext.getConfiguration(); - } - - @Override - @SuppressFBWarnings( - value = "PATH_TRAVERSAL_IN", - justification = "The location of the configuration comes from a running configuration.") - public String getConfigLocationUri() { - if (loggerContext.getConfigLocation() != null) { - return String.valueOf(loggerContext.getConfigLocation()); - } - if (getConfigName() != null) { - return String.valueOf(new File(getConfigName()).toURI()); - } - return Strings.EMPTY; - } - - @Override - @SuppressFBWarnings( - value = {"URLCONNECTION_SSRF_FD", "PATH_TRAVERSAL_IN"}, - justification = "This method should only be called by a secure JMX connection.") - public void setConfigLocationUri(final String configLocation) throws URISyntaxException, IOException { - if (configLocation == null || configLocation.isEmpty()) { - throw new IllegalArgumentException("Missing configuration location"); - } - LOGGER.debug("---------"); - LOGGER.debug("Remote request to reconfigure using location " + configLocation); - final File configFile = new File(configLocation); - ConfigurationSource configSource = null; - if (configFile.exists()) { - LOGGER.debug("Opening config file {}", configFile.getAbsolutePath()); - configSource = new ConfigurationSource(new FileInputStream(configFile), configFile); - } else { - final URL configURL = new URL(configLocation); - LOGGER.debug("Opening config URL {}", configURL); - configSource = new ConfigurationSource(configURL.openStream(), configURL); - } - final Configuration config = loggerContext.getConfiguration(configSource); - loggerContext.start(config); - LOGGER.debug("Completed remote request to reconfigure."); - } - - @Override - public String getConfigText() throws IOException { - return getConfigText(StandardCharsets.UTF_8.name()); - } - - @Override - @SuppressFBWarnings( - value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", - justification = "JMX should be considered a trusted channel.") - public String getConfigText(final String charsetName) throws IOException { - try { - final ConfigurationSource source = loggerContext.getConfiguration().getConfigurationSource(); - final ConfigurationSource copy = source.resetInputStream(); - final Charset charset = Charset.forName(charsetName); - return readContents(copy.getInputStream(), charset); - } catch (final Exception ex) { - final StringWriter sw = new StringWriter(BUFFER_SIZE); - ex.printStackTrace(new PrintWriter(sw)); - return sw.toString(); - } - } - - /** - * Returns the contents of the specified input stream as a String. - * - * @param in stream to read from - * @param charset MUST not be null - * @return stream contents - * @throws IOException if a problem occurred reading from the stream. - */ - private String readContents(final InputStream in, final Charset charset) throws IOException { - Reader reader = null; - try { - reader = new InputStreamReader(in, charset); - final StringBuilder result = new StringBuilder(TEXT_BUFFER); - final char[] buff = new char[PAGE]; - int count = -1; - while ((count = reader.read(buff)) >= 0) { - result.append(buff, 0, count); - } - return result.toString(); - } finally { - Closer.closeSilently(in); - Closer.closeSilently(reader); - } - } - - @Override - public void setConfigText(final String configText, final String charsetName) { - LOGGER.debug("---------"); - LOGGER.debug("Remote request to reconfigure from config text."); - - try { - final InputStream in = new ByteArrayInputStream(configText.getBytes(charsetName)); - final ConfigurationSource source = new ConfigurationSource(in); - final Configuration updated = loggerContext.getConfiguration(source); - loggerContext.start(updated); - LOGGER.debug("Completed remote request to reconfigure from config text."); - } catch (final Exception ex) { - final String msg = "Could not reconfigure from config text"; - LOGGER.error(msg, ex); - throw new IllegalArgumentException(msg, ex); - } - } - - @Override - public String getConfigName() { - return getConfig().getName(); - } - - @Override - public String getConfigClassName() { - return getConfig().getClass().getName(); - } - - @Override - public String getConfigFilter() { - return String.valueOf(getConfig().getFilter()); - } - - @Override - public Map getConfigProperties() { - return getConfig().getProperties(); - } - - /** - * Returns the {@code ObjectName} of this mbean. - * - * @return the {@code ObjectName} - * @see LoggerContextAdminMBean#PATTERN - */ - @Override - public ObjectName getObjectName() { - return objectName; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java deleted file mode 100644 index 9f5678c1134..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java +++ /dev/null @@ -1,169 +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.jmx; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Map; -import javax.management.ObjectName; - -/** - * The MBean interface for monitoring and managing a {@code LoggerContext}. - */ -public interface LoggerContextAdminMBean { - /** - * ObjectName pattern ({@value} ) for LoggerContextAdmin MBeans. This - * pattern contains a variable, which is the name of the logger context. - *

- * You can find all registered LoggerContextAdmin MBeans like this: - *

- * - *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(LoggerContextAdminMBean.PATTERN, "*");
-     * Set<ObjectName> loggerContextNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * Some characters are not allowed in ObjectNames. The logger context name - * may be quoted. When LoggerContextAdmin MBeans are registered, their - * ObjectNames are created using this pattern as follows: - *

- * - *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String name = String.format(PATTERN, ctxName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * - * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s"; - - /** - * Notification that the {@code Configuration} of the instrumented - * {@code LoggerContext} has been reconfigured. Notifications of this type - * ({@value} ) do not carry a message or user data. - */ - String NOTIF_TYPE_RECONFIGURED = "com.apache.logging.log4j.core.jmx.config.reconfigured"; - - /** - * Returns the {@code ObjectName} that this MBean is registered with in the - * MBean server. - */ - ObjectName getObjectName(); - - /** - * Returns the status of the instrumented {@code LoggerContext}. - * - * @return the LoggerContext status. - */ - String getStatus(); - - /** - * Returns the name of the instrumented {@code LoggerContext}. - * - * @return the name of the instrumented {@code LoggerContext}. - */ - String getName(); - - /** - * Returns the configuration location URI as a String. - * - * @return the configuration location - */ - String getConfigLocationUri(); - - /** - * Sets the configuration location to the specified URI. This will cause the - * instrumented {@code LoggerContext} to reconfigure. - * - * @param configLocation location of the configuration file in - * {@link java.net.URI} format. - * @throws URISyntaxException if the format of the specified - * configLocationURI is incorrect - * @throws IOException if an error occurred reading the specified location - */ - void setConfigLocationUri(String configLocation) throws URISyntaxException, IOException; - - /** - * Returns the configuration text, which may be the contents of the - * configuration file or the text that was last set with a call to - * {@code setConfigText}. If reading a file, this method assumes the file's - * character encoding is UTF-8. - * - * @return the configuration text - * @throws IOException if a problem occurred reading the contents of the - * config file. - */ - String getConfigText() throws IOException; - - /** - * Returns the configuration text, which may be the contents of the - * configuration file or the text that was last set with a call to - * {@code setConfigText}. - * - * @param charsetName the encoding to use to convert the file's bytes into - * the resulting string. - * @return the configuration text - * @throws IOException if a problem occurred reading the contents of the - * config file. - */ - String getConfigText(String charsetName) throws IOException; - - /** - * Sets the configuration text. This does not replace the contents of the - * configuration file, but does cause the instrumented - * {@code LoggerContext} to be reconfigured with the specified text. - * - * @param configText the configuration text in XML or JSON format - * @param charsetName name of the {@code Charset} used to convert the - * specified configText to bytes - * @throws IllegalArgumentException if a problem occurs configuring from the - * specified text - */ - void setConfigText(String configText, String charsetName); - - /** - * Returns the name of the Configuration of the instrumented LoggerContext. - * - * @return the Configuration name - */ - String getConfigName(); - - /** - * Returns the class name of the {@code Configuration} of the instrumented - * LoggerContext. - * - * @return the class name of the {@code Configuration}. - */ - String getConfigClassName(); - - /** - * Returns a string description of all Filters configured in the - * {@code Configuration} of the instrumented LoggerContext. - * - * @return a string description of all Filters configured - */ - String getConfigFilter(); - - /** - * Returns a map with configured properties. - * - * @return a map with configured properties. - */ - Map getConfigProperties(); -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java deleted file mode 100644 index 4faeea35bb9..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java +++ /dev/null @@ -1,73 +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.jmx; - -import com.lmax.disruptor.RingBuffer; -import javax.management.ObjectName; - -/** - * Instruments an LMAX Disruptor ring buffer. - */ -public class RingBufferAdmin implements RingBufferAdminMBean { - - private final RingBuffer ringBuffer; - private final ObjectName objectName; - - public static RingBufferAdmin forAsyncLogger(final RingBuffer ringBuffer, final 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( - final RingBuffer ringBuffer, final String contextName, final 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(final RingBuffer ringBuffer, final String mbeanName) { - this.ringBuffer = ringBuffer; - try { - objectName = new ObjectName(mbeanName); - } catch (final Exception e) { - throw new IllegalStateException(e); - } - } - - @Override - public long getBufferSize() { - return ringBuffer == null ? 0 : ringBuffer.getBufferSize(); - } - - @Override - public long getRemainingCapacity() { - return ringBuffer == null ? 0 : 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; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java deleted file mode 100644 index fd6dbe96938..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdminMBean.java +++ /dev/null @@ -1,71 +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.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. - *

- * You can find the registered RingBufferAdmin MBean for the global AsyncLogger like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(RingBufferAdminMBean.PATTERN_ASYNC_LOGGER, "*");
-     * Set<ObjectName> asyncLoggerNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- */ - String PATTERN_ASYNC_LOGGER = Server.DOMAIN + ":type=%s,component=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. - *

- * You can find all registered RingBufferAdmin MBeans like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(RingBufferAdminMBean.PATTERN_ASYNC_LOGGER_CONFIG, "*", "*");
-     * Set<ObjectName> asyncConfigNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- */ - String PATTERN_ASYNC_LOGGER_CONFIG = Server.DOMAIN + ":type=%s,component=Loggers,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(); -} 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 deleted file mode 100644 index e7ee25c3d45..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java +++ /dev/null @@ -1,401 +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.jmx; - -import java.lang.management.ManagementFactory; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import org.apache.logging.log4j.LogManager; -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.AsyncLoggerConfig; -import org.apache.logging.log4j.core.async.AsyncLoggerContext; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.impl.Log4jContextFactory; -import org.apache.logging.log4j.core.impl.Log4jPropertyKey; -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.status.StatusLogger; -import org.apache.logging.log4j.util.Constants; -import org.apache.logging.log4j.util.PropertiesUtil; - -/** - * Creates MBeans to instrument various classes in the log4j class hierarchy. - *

- * All instrumentation for Log4j 2 classes can be disabled by setting system property {@code -Dlog4j2.disable.jmx=true}. - *

- */ -public final class Server { - - private static final String CONTEXT_NAME_ALL = "*"; - /** - * The domain part, or prefix ({@value}) of the {@code ObjectName} of all MBeans that instrument Log4J2 components. - */ - public static final String DOMAIN = "org.apache.logging.log4j2"; - - private static final String THREAD_NAME_PREFIX = "jmx.notif"; - private static final StatusLogger LOGGER = StatusLogger.getLogger(); - static final Executor executor = isJmxDisabled() ? null : createExecutor(); - - private Server() {} - - /** - * Returns either a {@code null} Executor (causing JMX notifications to be sent from the caller thread) or a daemon - * background thread Executor, depending on the value of system property "log4j2.jmx.notify.async". If this - * property is not set, use a {@code null} Executor for web apps to avoid memory leaks and other issues when the - * web app is restarted. - * @see LOG4J2-938 - */ - private static ExecutorService createExecutor() { - final boolean defaultAsync = !Constants.isWebApp(); - final boolean async = - PropertiesUtil.getProperties().getBooleanProperty(Log4jPropertyKey.JMX_NOTIFY_ASYNC, defaultAsync); - return async - ? Executors.newFixedThreadPool(1, Log4jThreadFactory.createDaemonThreadFactory(THREAD_NAME_PREFIX)) - : null; - } - - /** - * Either returns the specified name as is, or returns a quoted value containing the specified name with the special - * characters (comma, equals, colon, quote, asterisk, or question mark) preceded with a backslash. - * - * @param name the name to escape so it can be used as a value in an {@link ObjectName}. - * @return the escaped name - */ - public static String escape(final String name) { - final StringBuilder sb = new StringBuilder(name.length() * 2); - boolean needsQuotes = false; - for (int i = 0; i < name.length(); i++) { - final char c = name.charAt(i); - switch (c) { - case '\\': - case '*': - case '?': - case '\"': - // quote, star, question & backslash must be escaped - sb.append('\\'); - needsQuotes = true; // ... and can only appear in quoted value - break; - case ',': - case '=': - case ':': - // no need to escape these, but value must be quoted - needsQuotes = true; - break; - case '\r': - // drop \r characters: \\r gives "invalid escape sequence" - continue; - case '\n': - // replace \n characters with \\n sequence - sb.append("\\n"); - needsQuotes = true; - continue; - } - sb.append(c); - } - if (needsQuotes) { - sb.insert(0, '\"'); - sb.append('\"'); - } - return sb.toString(); - } - - private static boolean isJmxDisabled() { - return !PropertiesUtil.getProperties().getBooleanProperty(Log4jPropertyKey.JMX_ENABLED, true); - } - - public static void reregisterMBeansAfterReconfigure() { - // avoid creating Platform MBean Server if JMX disabled - if (isJmxDisabled()) { - LOGGER.debug("JMX disabled for Log4j2. Not registering MBeans."); - return; - } - reregisterMBeansAfterReconfigure(ManagementFactory.getPlatformMBeanServer()); - } - - public static void reregisterMBeansAfterReconfigure(final MBeanServer mbs) { - if (isJmxDisabled()) { - LOGGER.debug("JMX disabled for Log4j2. Not registering MBeans."); - return; - } - - // now provide instrumentation for the newly configured - // LoggerConfigs and Appenders - try { - final ContextSelector selector = getContextSelector(); - if (selector == null) { - LOGGER.debug("Could not register MBeans: no ContextSelector found."); - return; - } - LOGGER.trace("Reregistering MBeans after reconfigure. Selector={}", selector); - final List contexts = selector.getLoggerContexts(); - int i = 0; - for (final LoggerContext ctx : contexts) { - LOGGER.trace("Reregistering context ({}/{}): '{}' {}", ++i, contexts.size(), ctx.getName(), ctx); - // first unregister the context and all nested loggers, - // appenders, statusLogger, contextSelector, ring buffers... - unregisterLoggerContext(ctx.getName(), mbs); - - final LoggerContextAdmin mbean = new LoggerContextAdmin(ctx, executor); - register(mbs, mbean, mbean.getObjectName()); - - if (ctx instanceof AsyncLoggerContext) { - final RingBufferAdmin rbmbean = ((AsyncLoggerContext) ctx).createRingBufferAdmin(); - if (rbmbean.getBufferSize() > 0) { - // don't register if Disruptor not started (DefaultConfiguration: config not found) - register(mbs, rbmbean, rbmbean.getObjectName()); - } - } - - // register the status logger and the context selector - // repeatedly - // for each known context: if one context is unregistered, - // these MBeans should still be available for the other - // contexts. - registerStatusLogger(ctx.getName(), mbs, executor); - registerContextSelector(ctx.getName(), selector, mbs, executor); - - registerLoggerConfigs(ctx, mbs, executor); - registerAppenders(ctx, mbs, executor); - } - } catch (final Exception ex) { - LOGGER.error("Could not register mbeans", ex); - } - } - - /** - * Unregister all log4j MBeans from the platform MBean server. - */ - public static void unregisterMBeans() { - if (isJmxDisabled()) { - LOGGER.debug("JMX disabled for Log4j2. Not unregistering MBeans."); - return; - } - unregisterMBeans(ManagementFactory.getPlatformMBeanServer()); - } - - /** - * Unregister all log4j MBeans from the specified MBean server. - * - * @param mbs the MBean server to unregister from. - */ - public static void unregisterMBeans(final MBeanServer mbs) { - if (mbs != null) { - unregisterStatusLogger(CONTEXT_NAME_ALL, mbs); - unregisterContextSelector(CONTEXT_NAME_ALL, mbs); - unregisterContexts(mbs); - unregisterLoggerConfigs(CONTEXT_NAME_ALL, mbs); - unregisterAsyncLoggerRingBufferAdmins(CONTEXT_NAME_ALL, mbs); - unregisterAsyncLoggerConfigRingBufferAdmins(CONTEXT_NAME_ALL, mbs); - unregisterAppenders(CONTEXT_NAME_ALL, mbs); - unregisterAsyncAppenders(CONTEXT_NAME_ALL, mbs); - } - } - - /** - * Returns the {@code ContextSelector} of the current {@code Log4jContextFactory}. - * - * @return the {@code ContextSelector} of the current {@code Log4jContextFactory} - */ - private static ContextSelector getContextSelector() { - final LoggerContextFactory factory = LogManager.getFactory(); - if (factory instanceof Log4jContextFactory) { - return ((Log4jContextFactory) factory).getSelector(); - } - return null; - } - - /** - * Unregisters all MBeans associated with the specified logger context (including MBeans for {@code LoggerConfig}s - * and {@code Appender}s from the platform MBean server. - * - * @param loggerContextName name of the logger context to unregister - */ - public static void unregisterLoggerContext(final String loggerContextName) { - if (loggerContextName != null) { - if (isJmxDisabled()) { - LOGGER.debug("JMX disabled for Log4j2. Not unregistering MBeans."); - return; - } - final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - unregisterLoggerContext(loggerContextName, mbs); - } - } - - /** - * Unregisters all MBeans associated with the specified logger context (including MBeans for {@code LoggerConfig}s - * and {@code Appender}s from the platform MBean server. - * - * @param contextName name of the logger context to unregister - * @param mbs the MBean Server to unregister the instrumented objects from - */ - public static void unregisterLoggerContext(final String contextName, final MBeanServer mbs) { - final String search = String.format(LoggerContextAdminMBean.PATTERN, escape(contextName)); - unregisterAllMatching(search, mbs); // unregister context mbean - - // now unregister all MBeans associated with this logger context - unregisterStatusLogger(contextName, mbs); - unregisterContextSelector(contextName, mbs); - unregisterLoggerConfigs(contextName, mbs); - unregisterAppenders(contextName, mbs); - unregisterAsyncAppenders(contextName, mbs); - unregisterAsyncLoggerRingBufferAdmins(contextName, mbs); - unregisterAsyncLoggerConfigRingBufferAdmins(contextName, mbs); - } - - private static void registerStatusLogger(final String contextName, final MBeanServer mbs, final Executor executor) - throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - - final StatusLoggerAdmin mbean = new StatusLoggerAdmin(contextName, executor); - register(mbs, mbean, mbean.getObjectName()); - } - - private static void registerContextSelector( - final String contextName, final ContextSelector selector, final MBeanServer mbs, final Executor executor) - throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - - final ContextSelectorAdmin mbean = new ContextSelectorAdmin(contextName, selector); - register(mbs, mbean, mbean.getObjectName()); - } - - private static void unregisterStatusLogger(final String contextName, final MBeanServer mbs) { - final String search = String.format(StatusLoggerAdminMBean.PATTERN, escape(contextName)); - unregisterAllMatching(search, mbs); - } - - private static void unregisterContextSelector(final String contextName, final MBeanServer mbs) { - final String search = String.format(ContextSelectorAdminMBean.PATTERN, escape(contextName)); - unregisterAllMatching(search, mbs); - } - - private static void unregisterLoggerConfigs(final String contextName, final MBeanServer mbs) { - final String pattern = LoggerConfigAdminMBean.PATTERN; - final String search = String.format(pattern, escape(contextName), "*"); - unregisterAllMatching(search, mbs); - } - - private static void unregisterContexts(final MBeanServer mbs) { - final String pattern = LoggerContextAdminMBean.PATTERN; - final String search = String.format(pattern, "*"); - unregisterAllMatching(search, mbs); - } - - private static void unregisterAppenders(final String contextName, final MBeanServer mbs) { - final String pattern = AppenderAdminMBean.PATTERN; - final String search = String.format(pattern, escape(contextName), "*"); - unregisterAllMatching(search, mbs); - } - - private static void unregisterAsyncAppenders(final String contextName, final MBeanServer mbs) { - final String pattern = AsyncAppenderAdminMBean.PATTERN; - final String search = String.format(pattern, escape(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, escape(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, escape(contextName), "*"); - unregisterAllMatching(search2, mbs); - } - - private static void unregisterAllMatching(final String search, final MBeanServer mbs) { - try { - final ObjectName pattern = new ObjectName(search); - final Set found = mbs.queryNames(pattern, null); - if (found == null || found.isEmpty()) { - LOGGER.trace("Unregistering but no MBeans found matching '{}'", search); - } else { - LOGGER.trace("Unregistering {} MBeans: {}", found.size(), found); - } - if (found != null) { - for (final ObjectName objectName : found) { - mbs.unregisterMBean(objectName); - } - } - } catch (final InstanceNotFoundException ex) { - LOGGER.debug("Could not unregister MBeans for " + search + ". Ignoring " + ex); - } catch (final Exception ex) { - LOGGER.error("Could not unregister MBeans for " + search, ex); - } - } - - private static void registerLoggerConfigs(final LoggerContext ctx, final MBeanServer mbs, final Executor executor) - throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - - final Map map = ctx.getConfiguration().getLoggers(); - for (final String name : map.keySet()) { - final LoggerConfig cfg = map.get(name); - final LoggerConfigAdmin mbean = new LoggerConfigAdmin(ctx, cfg); - register(mbs, mbean, mbean.getObjectName()); - - if (cfg instanceof AsyncLoggerConfig) { - final AsyncLoggerConfig async = (AsyncLoggerConfig) cfg; - final RingBufferAdmin rbmbean = async.createRingBufferAdmin(ctx.getName()); - register(mbs, rbmbean, rbmbean.getObjectName()); - } - } - } - - private static void registerAppenders(final LoggerContext ctx, final MBeanServer mbs, final Executor executor) - throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - - final Map map = ctx.getConfiguration().getAppenders(); - for (final String name : map.keySet()) { - final Appender appender = map.get(name); - - if (appender instanceof AsyncAppender) { - final AsyncAppender async = ((AsyncAppender) appender); - final AsyncAppenderAdmin mbean = new AsyncAppenderAdmin(ctx.getName(), async); - register(mbs, mbean, mbean.getObjectName()); - } else { - final AppenderAdmin mbean = new AppenderAdmin(ctx.getName(), appender); - register(mbs, mbean, mbean.getObjectName()); - } - } - } - - private static void register(final MBeanServer mbs, final Object mbean, final ObjectName objectName) - throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - if (mbs.isRegistered(objectName)) { - try { - mbs.unregisterMBean(objectName); - } catch (MBeanRegistrationException | InstanceNotFoundException ex) { - LOGGER.trace("Failed to unregister MBean {}", objectName); - } - } - LOGGER.debug("Registering MBean {}", objectName); - mbs.registerMBean(mbean, objectName); - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java deleted file mode 100644 index 03611c6c104..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java +++ /dev/null @@ -1,171 +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.jmx; - -import java.io.IOException; -import java.util.List; -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.Level; -import org.apache.logging.log4j.status.StatusData; -import org.apache.logging.log4j.status.StatusListener; -import org.apache.logging.log4j.status.StatusLogger; - -/** - * Implementation of the {@code StatusLoggerAdminMBean} interface. - */ -public class StatusLoggerAdmin extends NotificationBroadcasterSupport - implements StatusListener, StatusLoggerAdminMBean { - - private final AtomicLong sequenceNo = new AtomicLong(); - private final ObjectName objectName; - private final String contextName; - private Level level = Level.WARN; - - /** - * Constructs a new {@code StatusLoggerAdmin} with the {@code Executor} to - * be used for sending {@code Notification}s asynchronously to listeners. - * - * @param contextName name of the LoggerContext under which to register this - * StatusLoggerAdmin. Note that the StatusLogger may be - * registered multiple times, once for each LoggerContext. In web - * containers, each web application has its own LoggerContext and - * by associating the StatusLogger with the LoggerContext, all - * associated MBeans can be unloaded when the web application is - * undeployed. - * @param executor used to send notifications asynchronously - */ - public StatusLoggerAdmin(final String contextName, final Executor executor) { - super(executor, createNotificationInfo()); - this.contextName = contextName; - try { - final String mbeanName = String.format(PATTERN, Server.escape(contextName)); - objectName = new ObjectName(mbeanName); - } catch (final Exception e) { - throw new IllegalStateException(e); - } - removeListeners(contextName); - StatusLogger.getLogger().registerListener(this); - } - - /** - * Add listener to StatusLogger for this context, or replace it if it already exists. - * - * @param ctxName - */ - private void removeListeners(final String ctxName) { - final StatusLogger logger = StatusLogger.getLogger(); - final Iterable listeners = logger.getListeners(); - // Remove any StatusLoggerAdmin listeners already registered for this context - for (final StatusListener statusListener : listeners) { - if (statusListener instanceof StatusLoggerAdmin) { - final StatusLoggerAdmin adminListener = (StatusLoggerAdmin) statusListener; - if (ctxName != null && ctxName.equals(adminListener.contextName)) { - logger.removeListener(adminListener); - } - } - } - } - - private static MBeanNotificationInfo createNotificationInfo() { - final String[] notifTypes = new String[] {NOTIF_TYPE_DATA, NOTIF_TYPE_MESSAGE}; - final String name = Notification.class.getName(); - final String description = "StatusLogger has logged an event"; - return new MBeanNotificationInfo(notifTypes, name, description); - } - - @Override - public String[] getStatusDataHistory() { - final List data = getStatusData(); - final String[] result = new String[data.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = data.get(i).getFormattedStatus(); - } - return result; - } - - @Override - public List getStatusData() { - return StatusLogger.getLogger().getStatusData(); - } - - @Override - public String getLevel() { - return this.level.name(); - } - - @Override - public Level getStatusLevel() { - return this.level; - } - - @Override - public void setLevel(final String level) { - this.level = Level.toLevel(level, Level.ERROR); - } - - @Override - public String getContextName() { - return contextName; - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.logging.log4j.status.StatusListener#log(org.apache.logging - * .log4j.status.StatusData) - */ - @Override - public void log(final StatusData data) { - final Notification notifMsg = new Notification( - NOTIF_TYPE_MESSAGE, getObjectName(), nextSeqNo(), nowMillis(), data.getFormattedStatus()); - sendNotification(notifMsg); - - final Notification notifData = new Notification(NOTIF_TYPE_DATA, getObjectName(), nextSeqNo(), nowMillis()); - notifData.setUserData(data); - sendNotification(notifData); - } - - /** - * Returns the {@code ObjectName} of this mbean. - * - * @return the {@code ObjectName} - * @see StatusLoggerAdminMBean#PATTERN - */ - @Override - public ObjectName getObjectName() { - return objectName; - } - - private long nextSeqNo() { - return sequenceNo.getAndIncrement(); - } - - private long nowMillis() { - return System.currentTimeMillis(); - } - - @Override - public void close() throws IOException { - // nothing to close here - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdminMBean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdminMBean.java deleted file mode 100644 index 650e327e6a1..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdminMBean.java +++ /dev/null @@ -1,119 +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.jmx; - -import java.util.List; -import javax.management.ObjectName; -import org.apache.logging.log4j.status.StatusData; - -/** - * The MBean interface for monitoring and managing the {@code StatusLogger}. - */ -public interface StatusLoggerAdminMBean { - /** - * ObjectName pattern ({@value}) for StatusLoggerAdmin MBeans. - * This pattern contains a variable, which is the name of the logger context. - *

- * You can find all registered StatusLoggerAdmin MBeans like this: - *

- *
-     * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-     * String pattern = String.format(StatusLoggerAdminMBean.PATTERN, "*");
-     * Set<ObjectName> statusLoggerNames = mbs.queryNames(new ObjectName(pattern), null);
-     * 
- *

- * Some characters are not allowed in ObjectNames. The logger context name - * may be quoted. When StatusLoggerAdmin MBeans are - * registered, their ObjectNames are created using this pattern as follows: - *

- *
-     * String ctxName = Server.escape(loggerContext.getName());
-     * String name = String.format(PATTERN, ctxName);
-     * ObjectName objectName = new ObjectName(name);
-     * 
- * @see Server#escape(String) - */ - String PATTERN = Server.DOMAIN + ":type=%s,component=StatusLogger"; - - /** - * Notifications with this type have a {@code StatusData} userData object - * and a {@code null} message. - */ - String NOTIF_TYPE_DATA = "com.apache.logging.log4j.core.jmx.statuslogger.data"; - - /** - * Notifications with this type have a formatted status data message string - * but no {@code StatusData} in their userData field. - */ - String NOTIF_TYPE_MESSAGE = "com.apache.logging.log4j.core.jmx.statuslogger.message"; - - /** - * Returns the {@code ObjectName} that this status logger mbean is registered with. - * @return the ObjectName of this StatusLogger MBean - */ - ObjectName getObjectName(); - - /** - * Returns a list with the most recent {@code StatusData} objects in the - * status history. The list has up to 200 entries by default but the length - * can be configured with system property {@code "log4j2.status.entries"}. - *

- * Note that the returned objects may contain {@code Throwable}s from - * external libraries. - *

- *

- * JMX clients calling this method must be prepared to deal with the errors - * that occur if they do not have the class definition for such - * {@code Throwable}s in their classpath. - *

- * - * @return the most recent messages logged by the {@code StatusLogger}. - */ - List getStatusData(); - - /** - * Returns a string array with the most recent messages in the status - * history. The list has up to 200 entries by default but the length can be - * configured with system property {@code "log4j2.status.entries"}. - * - * @return the most recent messages logged by the {@code StatusLogger}. - */ - String[] getStatusDataHistory(); - - /** - * Returns the {@code StatusLogger} level as a String. - * - * @return the {@code StatusLogger} level. - */ - String getLevel(); - - /** - * Sets the {@code StatusLogger} level to the specified value. - * - * @param level the new {@code StatusLogger} level. - * @throws IllegalArgumentException if the specified level is not one of - * "OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", - * "ALL" - */ - void setLevel(String level); - - /** - * Returns the name of the LoggerContext that the {@code StatusLogger} is associated with. - * @return logger context name - */ - String getContextName(); -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/package-info.java deleted file mode 100644 index dca5a58940c..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/package-info.java +++ /dev/null @@ -1,25 +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. - */ -/** - * Log4j 2 JMX support. - */ -@Export -@Version("3.0.0") -package org.apache.logging.log4j.core.jmx; - -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; diff --git a/src/changelog/.3.x.x/remove_jmx.xml b/src/changelog/.3.x.x/remove_jmx.xml new file mode 100644 index 00000000000..e04bae30c85 --- /dev/null +++ b/src/changelog/.3.x.x/remove_jmx.xml @@ -0,0 +1,9 @@ + + + + Removed JMX support. + +