Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #4830 - Enabling JMX on jetty-slf4j-impl #4831

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ org.eclipse.jetty.LEVEL=INFO
#com.example.LEVEL=INFO
## Configure a level for specific logger
#com.example.MyComponent.LEVEL=INFO
## Enable JMX management of Jetty Logging
# org.eclipse.jetty.logging.jmx=true
## Configure JMX Context Name
# org.eclipse.jetty.logging.jmx.contextName=JettyServer
## Hide stacks traces in an arbitrary logger tree
#com.example.STACKS=false
2 changes: 2 additions & 0 deletions jetty-slf4j-impl/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@

requires transitive org.slf4j;

requires static java.management;

provides SLF4JServiceProvider with JettyLoggingServiceProvider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public void log(Marker marker, String fqcn, int levelInt, String message, Object
{
long timestamp = System.currentTimeMillis();
String threadName = Thread.currentThread().getName();
getAppender().emit(this, intToLevel(levelInt), timestamp, threadName, throwable, message, argArray);
getAppender().emit(this, LevelUtils.intToLevel(levelInt), timestamp, threadName, throwable, message, argArray);
}
}

Expand Down Expand Up @@ -636,43 +636,9 @@ private void emit(Level level, String msg, Throwable throwable)
getAppender().emit(this, level, timestamp, threadName, throwable, msg);
}

public static Level intToLevel(int level)
{
if (level >= JettyLogger.OFF)
return Level.ERROR;
if (level >= Level.ERROR.toInt())
return Level.ERROR;
if (level >= Level.WARN.toInt())
return Level.WARN;
if (level >= Level.INFO.toInt())
return Level.INFO;
if (level >= Level.DEBUG.toInt())
return Level.DEBUG;
if (level >= Level.TRACE.toInt())
return Level.TRACE;
return Level.TRACE; // everything else
}

public static String levelToString(int level)
{
if (level >= JettyLogger.OFF)
return "OFF";
if (level >= Level.ERROR.toInt())
return "ERROR";
if (level >= Level.WARN.toInt())
return "WARN";
if (level >= Level.INFO.toInt())
return "INFO";
if (level >= Level.DEBUG.toInt())
return "DEBUG";
if (level >= Level.TRACE.toInt())
return "TRACE";
return "OFF"; // everything else
}

@Override
public String toString()
{
return String.format("%s:%s:LEVEL=%s", JettyLogger.class.getSimpleName(), name, levelToString(level));
return String.format("%s:%s:LEVEL=%s", JettyLogger.class.getSimpleName(), name, LevelUtils.levelToString(level));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.function.Function;

import org.slf4j.event.Level;

Expand Down Expand Up @@ -82,7 +81,7 @@ public boolean getHideStacks(String name)
startName = startName.substring(0, startName.length() - SUFFIX_STACKS.length());
}

Boolean hideStacks = walkParentLoggerNames(startName, (key) ->
Boolean hideStacks = JettyLoggerFactory.walkParentLoggerNames(startName, (key) ->
{
String stacksBool = properties.getProperty(key + SUFFIX_STACKS);
if (stacksBool != null)
Expand Down Expand Up @@ -124,12 +123,12 @@ public int getLevel(String name)
startName = startName.substring(0, startName.length() - SUFFIX_LEVEL.length());
}

Integer level = walkParentLoggerNames(startName, (key) ->
Integer level = JettyLoggerFactory.walkParentLoggerNames(startName, (key) ->
{
String levelStr = properties.getProperty(key + SUFFIX_LEVEL);
if (levelStr != null)
String levelStr1 = properties.getProperty(key + SUFFIX_LEVEL);
if (levelStr1 != null)
{
return getLevelInt(key, levelStr);
return LevelUtils.getLevelInt(key, levelStr1);
}
return null;
});
Expand All @@ -140,7 +139,7 @@ public int getLevel(String name)
String levelStr = properties.getProperty("log" + SUFFIX_LEVEL);
if (levelStr != null)
{
level = getLevelInt("log", levelStr);
level = LevelUtils.getLevelInt("log", levelStr);
}
}

Expand Down Expand Up @@ -193,6 +192,11 @@ public JettyLoggerConfiguration load(ClassLoader loader)
});
}

public String getString(String key, String defValue)
{
return properties.getProperty(key, defValue);
}

public boolean getBoolean(String key, boolean defValue)
{
String val = properties.getProperty(key, Boolean.toString(defValue));
Expand All @@ -216,36 +220,6 @@ public int getInt(String key, int defValue)
}
}

private Integer getLevelInt(String levelSegment, String levelStr)
{
if (levelStr == null)
{
return null;
}

String levelName = levelStr.trim().toUpperCase(Locale.ENGLISH);
switch (levelName)
{
case "ALL":
return JettyLogger.ALL;
case "TRACE":
return Level.TRACE.toInt();
case "DEBUG":
return Level.DEBUG.toInt();
case "INFO":
return Level.INFO.toInt();
case "WARN":
return Level.WARN.toInt();
case "ERROR":
return Level.ERROR.toInt();
case "OFF":
return JettyLogger.OFF;
default:
System.err.println("Unknown JettyLogger/Slf4J Level [" + levelSegment + "]=[" + levelName + "], expecting only [ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF] as values.");
return null;
}
}

private URL getResource(ClassLoader loader, String resourceName)
{
if (loader == null)
Expand Down Expand Up @@ -303,30 +277,4 @@ private Properties readProperties(ClassLoader loader, String resourceName)
}
return null;
}

private <T> T walkParentLoggerNames(String startName, Function<String, T> nameFunction)
{
String nameSegment = startName;

// Checking with FQCN first, then each package segment from longest to shortest.
while ((nameSegment != null) && (nameSegment.length() > 0))
{
T ret = nameFunction.apply(nameSegment);
if (ret != null)
return ret;

// Trim and try again.
int idx = nameSegment.lastIndexOf('.');
if (idx >= 0)
{
nameSegment = nameSegment.substring(0, idx);
}
else
{
nameSegment = null;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.function.Function;

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;

public class JettyLoggerFactory implements ILoggerFactory
public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBean
{
private static final String ROOT_LOGGER_NAME = "";
private final JettyLoggerConfiguration configuration;
private final JettyLogger rootLogger;
private ConcurrentMap<String, JettyLogger> loggerMap;
private final ConcurrentMap<String, JettyLogger> loggerMap;

public JettyLoggerFactory(JettyLoggerConfiguration config)
{
Expand All @@ -41,9 +41,9 @@ public JettyLoggerFactory(JettyLoggerConfiguration config)

StdErrAppender appender = new StdErrAppender(configuration);

rootLogger = new JettyLogger(this, ROOT_LOGGER_NAME, appender);
loggerMap.put(ROOT_LOGGER_NAME, rootLogger);
rootLogger.setLevel(configuration.getLevel(ROOT_LOGGER_NAME));
rootLogger = new JettyLogger(this, Logger.ROOT_LOGGER_NAME, appender);
loggerMap.put(Logger.ROOT_LOGGER_NAME, rootLogger);
rootLogger.setLevel(configuration.getLevel(Logger.ROOT_LOGGER_NAME));
}

/**
Expand All @@ -54,7 +54,7 @@ public JettyLoggerFactory(JettyLoggerConfiguration config)
*/
public JettyLogger getJettyLogger(String name)
{
if (name.equals(ROOT_LOGGER_NAME))
if (name.equals(Logger.ROOT_LOGGER_NAME))
{
return getRootLogger();
}
Expand Down Expand Up @@ -179,4 +179,67 @@ protected static String condensePackageString(String classname)

return dense.toString();
}

public static <T> T walkParentLoggerNames(String startName, Function<String, T> nameFunction)
{
String nameSegment = startName;

// Checking with FQCN first, then each package segment from longest to shortest.
while ((nameSegment != null) && (nameSegment.length() > 0))
{
T ret = nameFunction.apply(nameSegment);
if (ret != null)
return ret;

// Trim and try again.
int idx = nameSegment.lastIndexOf('.');
if (idx >= 0)
{
nameSegment = nameSegment.substring(0, idx);
}
else
{
nameSegment = null;
}
}

return null;
}

@Override
public String[] getLoggerNames()
{
return loggerMap.keySet().toArray(new String[0]);
}

@Override
public int getLoggerCount()
{
return loggerMap.size();
}

@Override
public String getLoggerLevel(String loggerName)
{
return walkParentLoggerNames(loggerName, (key) ->
{
JettyLogger logger = loggerMap.get(key);
if (key != null)
{
return LevelUtils.levelToString(logger.getLevel());
}
return null;
});
}

@Override
public void setLoggerLevel(String loggerName, String levelName)
{
Integer levelInt = LevelUtils.getLevelInt(loggerName, levelName);
if (levelInt != null)
{
JettyLogger jettyLogger = getJettyLogger(loggerName);
jettyLogger.setLevel(levelInt);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.logging;

@SuppressWarnings("unused")
public interface JettyLoggerFactoryMBean
{
int getLoggerCount();

String[] getLoggerNames();

void setLoggerLevel(String loggerName, String levelName);

String getLoggerLevel(String loggerName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.logging;

import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class JettyLoggingJmx
{
public static void initialize(JettyLoggerConfiguration config, JettyLoggerFactory loggerFactory)
{
if (!config.getBoolean("org.eclipse.jetty.logging.jmx", false))
{
loggerFactory.getJettyLogger(JettyLoggingJmx.class.getName()).debug("JMX not enabled");
return;
}

try
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
String contextName = config.getString("org.eclipse.jetty.logging.jmx.contextName", "default");

ObjectName objName = new ObjectName(JettyLoggerFactory.class.getName() + ":name=" + contextName);
mbs.registerMBean(loggerFactory, objName);
}
catch (Throwable cause)
{
JettyLogger logger = loggerFactory.getJettyLogger(JettyLoggingJmx.class.getName());
logger.warn("java.management not available.");
logger.debug("java.management is not available", cause);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public void initialize()
loggerFactory = new JettyLoggerFactory(config);
markerFactory = new BasicMarkerFactory();
mdcAdapter = new NOPMDCAdapter(); // TODO: Provide Jetty Implementation?

JettyLoggingJmx.initialize(config, loggerFactory);
}

public JettyLoggerFactory getJettyLoggerFactory()
Expand Down
Loading