Skip to content

Commit

Permalink
Merge branch 'rl-1.1.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
lalmeras committed Aug 28, 2023
2 parents 57ac9e8 + b3eb61b commit 6b20432
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ target
out/
bin/
.*.swp
ecplise/
eclipse/
4 changes: 2 additions & 2 deletions jul-helper-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.iglooproject.components</groupId>
<artifactId>igloo-logging</artifactId>
<version>1.0.2</version>
<version>1.1.0</version>
</parent>

<artifactId>jul-helper-api</artifactId>
Expand Down Expand Up @@ -37,4 +37,4 @@
</plugins>
</reporting>

</project>
</project>
9 changes: 7 additions & 2 deletions jul-helper/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.iglooproject.components</groupId>
<artifactId>igloo-logging</artifactId>
<version>1.0.2</version>
<version>1.1.0</version>
</parent>

<artifactId>jul-helper</artifactId>
Expand All @@ -24,6 +24,11 @@
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
Expand Down Expand Up @@ -71,4 +76,4 @@
</plugins>
</reporting>

</project>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package igloo.julhelper.internal;

import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.LogManager;

import javax.management.ObjectName;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

import igloo.julhelper.jmx.JulLoggingManagerMBean;

/**
* # Usage
*
* Conditionally install {@link SLF4JBridgeHandler} and `igloo:type=LoggingManager,name=JulLoggingManager` JMX Bean.
*
* Behavior can be controlled with `skipJulSlf4jBridgeHandler` and `skipJulJmxHelper` init parameters.
* Default behavior is to add both helpers.
*
* `julKnownLoggersResourcePath` init parameter allows to point a resource for loading well-known JUL logger names.
* This file must contain a line by JUL logger. This list is used to conditionally apply logger updates from
* third-party components (like Log4j2LoggingManager), so that JUL logger configuration is applied only for loggers
* and children from this list. By default, `jul-helper/well-known-jul-loggers.txt` is used. You can disable
* this loading with the value `none`. Effective configuration can be retrieve from JMX bean.
*
* This listener can be added in `web.xml` by adding this extract among the first listeners (`context-param` may be
* omitted if default values are convenient):
*
* <pre>{@code
* <listener>
* <listener-class>igloo.julhelper.servlet.JulLoggingListener</listener-class>
* </listener>
* <context-param>
* <param-name>skipJulSlf4jBridgeHandler</param-name>
* <param-value>false</param-value>
* </context-param>
* <context-param>
* <param-name>skipJulJmxHelper</param-name>
* <param-value>false</param-value>
* </context-param>
* }</pre>
*
* # About SLF4JBridgeHandler
*
* Purpose of SLF4JBridgeHandler is to install a handler on the `java.util.logging` root logger. All event that can be
* forwarded from child logger and accepted by root logger level can then be handled by SLF4J.
*
* It implies that level must be set accordingly so that log event can be propagated to SLF4J bridge handler. Either:
*
* * Set a catch-all root level, and do not set level on any child. This configuration implies a performance hit as
* all log event are propagated;
* * Set a catch-all root level, set warning or error level to limit propagation of unwanted loggers. This allows to
* limit log event volume. This configuration needs to configure both JUL and SLF4J backend consistently;
* * Set a WARN root level, and attach {@link SLF4JBridgeHandler} on each targeted child logger. JUL and SLF4J
* backend need to be configured consistently.
*
* # About JUL JMX helper
*
* This JMX MBean allows to bind {@link SLF4JBridgeHandler} and set level on arbitrary loggers to activate logging
* during runtime.
*/
public abstract class AbstractJulLoggingListener {

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractJulLoggingListener.class);

private static final String PARAMETER_SKIP_JUL_SLF4J_BRIDGE_HANDLER = "skipJulSlf4jBridgeHandler";
private static final String PARAMETER_SKIP_JUL_JMX_HELPER = "skipJulJmxHelper";
private static final String PARAMETER_JUL_KNOWN_LOGGERS_RESOURCE_PATH = "julKnownLoggersResourcePath";

private ObjectName mbeanObjectName;

/**
* @see AbstractJulLoggingListener
*/
public void contextInitialized(CommonContextEvent sce) {
// "" triggers default loading
String julKnownLoggersResourcePath = Optional.ofNullable(sce.getInitParameter(PARAMETER_JUL_KNOWN_LOGGERS_RESOURCE_PATH)).orElse("");
if ("none".equalsIgnoreCase(julKnownLoggersResourcePath)) {
// disable loading
julKnownLoggersResourcePath = null;
}

if (!getBooleanParameter(sce, PARAMETER_SKIP_JUL_SLF4J_BRIDGE_HANDLER)) {
initSlf4jBridgeHandler();
}

if (!getBooleanParameter(sce, PARAMETER_SKIP_JUL_JMX_HELPER)) {
mbeanObjectName = JulLoggingManagerMBean.registerMBean(julKnownLoggersResourcePath);
}

LOGGER.info("jul-to-slf4j installed");
}

/**
* Install jul-to-slf4j bridge handler.
*/
private void initSlf4jBridgeHandler() {
LogManager.getLogManager().reset();
java.util.logging.Logger.getLogger("").setLevel(Level.WARNING);
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}

/**
* @see AbstractJulLoggingListener
*/
public void contextDestroyed() {
if (mbeanObjectName != null) {
JulLoggingManagerMBean.unregisterMBean(mbeanObjectName);
}
}

/**
* Extract boolean parameter named `paramName` from `sce`. Returns true only if parameter value is `true`.
*
* @param sce configuration provider. Required.
* @param paramName name of the boolean parameter to extract. Required.
* @return true if parameter string value is `true`. false for other values or missing parameter.
*/
private boolean getBooleanParameter(CommonContextEvent sce, String paramName) {
String param = sce.getInitParameter(paramName);
return Boolean.TRUE.toString().equals(param);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package igloo.julhelper.internal;

public interface CommonContextEvent {

String getInitParameter(String paramName);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package igloo.julhelper.internal;

public class JakartaContextEventWrapper implements CommonContextEvent {

private final jakarta.servlet.ServletContextEvent contextEvent;

public JakartaContextEventWrapper(jakarta.servlet.ServletContextEvent contextEvent) {
super();
this.contextEvent = contextEvent;
}

@Override
public String getInitParameter(String paramName) {
return contextEvent.getServletContext().getInitParameter(paramName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package igloo.julhelper.internal;

import javax.servlet.ServletContextEvent;

public class JavaxContextEventWrapper implements CommonContextEvent {

private final ServletContextEvent contextEvent;

public JavaxContextEventWrapper(ServletContextEvent contextEvent) {
super();
this.contextEvent = contextEvent;
}

@Override
public String getInitParameter(String paramName) {
return contextEvent.getServletContext().getInitParameter(paramName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package igloo.julhelper.servlet;

import igloo.julhelper.internal.AbstractJulLoggingListener;
import igloo.julhelper.internal.JakartaContextEventWrapper;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;

/**
* <code>jakarta.servlet</code> version.
*
* @see AbstractJulLoggingListener
*/
public class JakartaJulLoggingListener extends AbstractJulLoggingListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
super.contextInitialized(new JakartaContextEventWrapper(sce));
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
super.contextDestroyed();
}

}
Original file line number Diff line number Diff line change
@@ -1,132 +1,25 @@
package igloo.julhelper.servlet;

import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.LogManager;

import javax.management.ObjectName;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

import igloo.julhelper.jmx.JulLoggingManagerMBean;
import igloo.julhelper.internal.AbstractJulLoggingListener;
import igloo.julhelper.internal.JavaxContextEventWrapper;

/**
* # Usage
*
* Conditionally install {@link SLF4JBridgeHandler} and `igloo:type=LoggingManager,name=JulLoggingManager` JMX Bean.
*
* Behavior can be controlled with `skipJulSlf4jBridgeHandler` and `skipJulJmxHelper` init parameters.
* Default behavior is to add both helpers.
*
* `julKnownLoggersResourcePath` init parameter allows to point a resource for loading well-known JUL logger names.
* This file must contain a line by JUL logger. This list is used to conditionally apply logger updates from
* third-party components (like Log4j2LoggingManager), so that JUL logger configuration is applied only for loggers
* and children from this list. By default, `jul-helper/well-known-jul-loggers.txt` is used. You can disable
* this loading with the value `none`. Effective configuration can be retrieve from JMX bean.
*
* This listener can be added in `web.xml` by adding this extract among the first listeners (`context-param` may be
* omitted if default values are convenient):
*
* <pre>{@code
* <listener>
* <listener-class>igloo.julhelper.servlet.JulLoggingListener</listener-class>
* </listener>
* <context-param>
* <param-name>skipJulSlf4jBridgeHandler</param-name>
* <param-value>false</param-value>
* </context-param>
* <context-param>
* <param-name>skipJulJmxHelper</param-name>
* <param-value>false</param-value>
* </context-param>
* }</pre>
*
* # About SLF4JBridgeHandler
*
* Purpose of SLF4JBridgeHandler is to install a handler on the `java.util.logging` root logger. All event that can be
* forwarded from child logger and accepted by root logger level can then be handled by SLF4J.
* <code>javax.servlet</code> version.
*
* It implies that level must be set accordingly so that log event can be propagated to SLF4J bridge handler. Either:
*
* * Set a catch-all root level, and do not set level on any child. This configuration implies a performance hit as
* all log event are propagated;
* * Set a catch-all root level, set warning or error level to limit propagation of unwanted loggers. This allows to
* limit log event volume. This configuration needs to configure both JUL and SLF4J backend consistently;
* * Set a WARN root level, and attach {@link SLF4JBridgeHandler} on each targeted child logger. JUL and SLF4J
* backend need to be configured consistently.
*
* # About JUL JMX helper
*
* This JMX MBean allows to bind {@link SLF4JBridgeHandler} and set level on arbitrary loggers to activate logging
* during runtime.
* @see AbstractJulLoggingListener
*/
public class JulLoggingListener implements ServletContextListener {

private static final Logger LOGGER = LoggerFactory.getLogger(JulLoggingListener.class);

private static final String PARAMETER_SKIP_JUL_SLF4J_BRIDGE_HANDLER = "skipJulSlf4jBridgeHandler";
private static final String PARAMETER_SKIP_JUL_JMX_HELPER = "skipJulJmxHelper";
private static final String PARAMETER_JUL_KNOWN_LOGGERS_RESOURCE_PATH = "julKnownLoggersResourcePath";

private ObjectName mbeanObjectName;
public class JulLoggingListener extends AbstractJulLoggingListener implements ServletContextListener {

/**
* @see JulLoggingListener
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
// "" triggers default loading
String julKnownLoggersResourcePath = Optional.ofNullable(sce.getServletContext().getInitParameter(PARAMETER_JUL_KNOWN_LOGGERS_RESOURCE_PATH)).orElse("");
if ("none".equalsIgnoreCase(julKnownLoggersResourcePath)) {
// disable loading
julKnownLoggersResourcePath = null;
}

if (!getBooleanParameter(sce, PARAMETER_SKIP_JUL_SLF4J_BRIDGE_HANDLER)) {
initSlf4jBridgeHandler();
}

if (!getBooleanParameter(sce, PARAMETER_SKIP_JUL_JMX_HELPER)) {
mbeanObjectName = JulLoggingManagerMBean.registerMBean(julKnownLoggersResourcePath);
}

LOGGER.info("jul-to-slf4j installed");
public void contextInitialized(javax.servlet.ServletContextEvent sce) {
super.contextInitialized(new JavaxContextEventWrapper(sce));
}

/**
* Install jul-to-slf4j bridge handler.
*/
private void initSlf4jBridgeHandler() {
LogManager.getLogManager().reset();
java.util.logging.Logger.getLogger("").setLevel(Level.WARNING);
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}

/**
* @see JulLoggingListener
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (mbeanObjectName != null) {
JulLoggingManagerMBean.unregisterMBean(mbeanObjectName);
}
}

/**
* Extract boolean parameter named `paramName` from `sce`. Returns true only if parameter value is `true`.
*
* @param sce configuration provider. Required.
* @param paramName name of the boolean parameter to extract. Required.
* @return true if parameter string value is `true`. false for other values or missing parameter.
*/
private boolean getBooleanParameter(ServletContextEvent sce, String paramName) {
String param = sce.getServletContext().getInitParameter(paramName);
return Boolean.TRUE.toString().equals(param);
public void contextDestroyed(javax.servlet.ServletContextEvent sce) {
super.contextDestroyed();
}

}
Loading

0 comments on commit 6b20432

Please sign in to comment.