Issue #5872 - JMX DynamicMBean for jetty-slf4j-impl
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
parent
6769a83d3d
commit
37e7361706
|
@ -18,6 +18,12 @@
|
|||
<Arg>
|
||||
<Ref refid="MBeanServer" />
|
||||
</Arg>
|
||||
<Call name="beanAdded">
|
||||
<Arg/>
|
||||
<Arg>
|
||||
<Get name="ILoggerFactory" class="org.slf4j.LoggerFactory"/>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -18,6 +18,7 @@ module org.eclipse.jetty.logging
|
|||
{
|
||||
exports org.eclipse.jetty.logging;
|
||||
|
||||
requires transitive java.management;
|
||||
requires transitive org.slf4j;
|
||||
|
||||
provides SLF4JServiceProvider with JettyLoggingServiceProvider;
|
||||
|
|
|
@ -19,15 +19,28 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBean
|
||||
public class JettyLoggerFactory implements ILoggerFactory, DynamicMBean, JettyLoggerFactoryMBean
|
||||
{
|
||||
private final JettyLoggerConfiguration configuration;
|
||||
private final JettyLogger rootLogger;
|
||||
private final ConcurrentMap<String, JettyLogger> loggerMap;
|
||||
private MBeanInfo mBeanInfo;
|
||||
|
||||
public JettyLoggerFactory(JettyLoggerConfiguration config)
|
||||
{
|
||||
|
@ -129,20 +142,17 @@ public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBe
|
|||
return nameFunction.apply(Logger.ROOT_LOGGER_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLoggerNames()
|
||||
{
|
||||
TreeSet<String> names = new TreeSet<>(loggerMap.keySet());
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoggerCount()
|
||||
{
|
||||
return loggerMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoggerLevel(String loggerName)
|
||||
{
|
||||
return walkParentLoggerNames(loggerName, key ->
|
||||
|
@ -154,7 +164,6 @@ public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBe
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLoggerLevel(String loggerName, String levelName)
|
||||
{
|
||||
JettyLevel level = JettyLoggerConfiguration.toJettyLevel(loggerName, levelName);
|
||||
|
@ -166,4 +175,166 @@ public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBe
|
|||
jettyLogger.setLevel(level);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) throws AttributeNotFoundException
|
||||
{
|
||||
Objects.requireNonNull(name, "Attribute Name");
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "LoggerNames":
|
||||
return getLoggerNames();
|
||||
case "LoggerCount":
|
||||
return getLoggerCount();
|
||||
default:
|
||||
throw new AttributeNotFoundException("Cannot find " + name + " attribute in " + this.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException
|
||||
{
|
||||
Objects.requireNonNull(attribute, "attribute");
|
||||
String name = attribute.getName();
|
||||
// No attributes are writable
|
||||
throw new AttributeNotFoundException("Cannot set attribute " + name + " because it is read-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(String[] attributeNames)
|
||||
{
|
||||
Objects.requireNonNull(attributeNames, "attributeNames[]");
|
||||
|
||||
AttributeList ret = new AttributeList();
|
||||
if (attributeNames.length == 0)
|
||||
return ret;
|
||||
|
||||
for (String name : attributeNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object value = getAttribute(name);
|
||||
ret.add(new Attribute(name, value));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// nothing much we can do, this method has no throwables, and we cannot use logging here.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList setAttributes(AttributeList attributes)
|
||||
{
|
||||
Objects.requireNonNull(attributes, "attributes");
|
||||
|
||||
AttributeList ret = new AttributeList();
|
||||
|
||||
if (attributes.isEmpty())
|
||||
return ret;
|
||||
|
||||
for (Attribute attr : attributes.asList())
|
||||
{
|
||||
try
|
||||
{
|
||||
setAttribute(attr);
|
||||
String name = attr.getName();
|
||||
Object value = getAttribute(name);
|
||||
ret.add(new Attribute(name, value));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// nothing much we can do, this method has no throwables, and we cannot use logging here.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
setLoggerLevel(String loggerName, String levelName);
|
||||
String getLoggerLevel(String loggerName);
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException
|
||||
{
|
||||
Objects.requireNonNull(actionName, "Action Name");
|
||||
|
||||
switch (actionName)
|
||||
{
|
||||
case "setLoggerLevel":
|
||||
{
|
||||
String loggerName = (String)params[0];
|
||||
String level = (String)params[1];
|
||||
return setLoggerLevel(loggerName, level);
|
||||
}
|
||||
case "getLoggerLevel":
|
||||
{
|
||||
String loggerName = (String)params[0];
|
||||
return getLoggerLevel(loggerName);
|
||||
}
|
||||
default:
|
||||
throw new ReflectionException(
|
||||
new NoSuchMethodException(actionName),
|
||||
"Cannot find the operation " + actionName + " in " + this.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo()
|
||||
{
|
||||
if (mBeanInfo == null)
|
||||
{
|
||||
MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[2];
|
||||
|
||||
attrs[0] = new MBeanAttributeInfo(
|
||||
"LoggerCount",
|
||||
"java.lang.Integer",
|
||||
"Count of Registered Loggers by Name.",
|
||||
true,
|
||||
false,
|
||||
false);
|
||||
attrs[1] = new MBeanAttributeInfo(
|
||||
"LoggerNames",
|
||||
"java.lang.String[]",
|
||||
"List of Registered Loggers by Name.",
|
||||
true,
|
||||
false,
|
||||
false);
|
||||
|
||||
MBeanOperationInfo[] operations = new MBeanOperationInfo[]{
|
||||
new MBeanOperationInfo(
|
||||
"setLoggerLevel",
|
||||
"Set the logging level at the named logger",
|
||||
new MBeanParameterInfo[]{
|
||||
new MBeanParameterInfo("loggerName", "java.lang.String", "The name of the logger"),
|
||||
new MBeanParameterInfo("level", "java.lang.String", "The name of the level [DEBUG, INFO, WARN, ERROR]")
|
||||
},
|
||||
"boolean",
|
||||
MBeanOperationInfo.ACTION
|
||||
),
|
||||
new MBeanOperationInfo(
|
||||
"getLoggerLevel",
|
||||
"Get the logging level at the named logger",
|
||||
new MBeanParameterInfo[]{
|
||||
new MBeanParameterInfo("loggerName", "java.lang.String", "The name of the logger")
|
||||
},
|
||||
"java.lang.String",
|
||||
MBeanOperationInfo.INFO
|
||||
)
|
||||
};
|
||||
|
||||
mBeanInfo = new MBeanInfo(this.getClass().getName(),
|
||||
"Jetty Slf4J Logger Factory",
|
||||
attrs,
|
||||
new MBeanConstructorInfo[0],
|
||||
operations,
|
||||
new MBeanNotificationInfo[0]);
|
||||
}
|
||||
return mBeanInfo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,18 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -35,18 +40,24 @@ public class JMXTest
|
|||
{
|
||||
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
Properties props = new Properties();
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
JettyLoggerFactory loggerFactory = new JettyLoggerFactory(config);
|
||||
|
||||
ObjectName objectName = ObjectName.getInstance("org.eclipse.jetty.logging", "type", JettyLoggerFactory.class.getSimpleName().toLowerCase(Locale.ENGLISH));
|
||||
mbeanServer.registerMBean(loggerFactory, objectName);
|
||||
mbeanServer.registerMBean(LoggerFactory.getILoggerFactory(), objectName);
|
||||
|
||||
// Verify MBeanInfo
|
||||
MBeanInfo beanInfo = mbeanServer.getMBeanInfo(objectName);
|
||||
|
||||
MBeanAttributeInfo[] attributeInfos = beanInfo.getAttributes();
|
||||
assertThat("MBeanAttributeInfo count", attributeInfos.length, is(2));
|
||||
|
||||
MBeanAttributeInfo attr = Stream.of(attributeInfos).filter((a) -> a.getName().equals("LoggerNames")).findFirst().orElseThrow();
|
||||
assertThat("attr", attr.getDescription(), is("List of Registered Loggers by Name."));
|
||||
|
||||
JettyLoggerFactoryMBean mbean = JMX.newMBeanProxy(mbeanServer, objectName, JettyLoggerFactoryMBean.class);
|
||||
|
||||
// Only the root logger.
|
||||
assertEquals(1, mbean.getLoggerCount());
|
||||
|
||||
JettyLoggerFactory loggerFactory = (JettyLoggerFactory)LoggerFactory.getILoggerFactory();
|
||||
JettyLogger child = loggerFactory.getJettyLogger("org.eclipse.jetty.logging");
|
||||
JettyLogger parent = loggerFactory.getJettyLogger("org.eclipse.jetty");
|
||||
assertEquals(3, mbean.getLoggerCount());
|
||||
|
|
Loading…
Reference in New Issue