All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dua3.utility.logging.log4j.LogUtilLog4J Maven / Gradle / Ivy

There is a newer version: 15.0.2
Show newest version
package com.dua3.utility.logging.log4j;

import com.dua3.utility.logging.LogLevel;
import com.dua3.utility.logging.LogUtil;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.spi.StandardLevel;

/**
 * A utility class for creating and managing Log4j appenders.
 * 

* Rerouting logging to Log4J
*

    *
  • JUL (java.util.logging): add {@code log4j-jul} to your dependencies and add a static initializer * block before declaring any Logger: *
     *        static {
     *            System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
     *        }
     *     
    *
  • SLF4J: add {@code log4j-slf4j2-impl} to your dependencies. Do not add any other logging implementation * based on SLF4J (i.e., SimpleLogger, Logback). *
*/ @SuppressWarnings("MagicCharacter") public final class LogUtilLog4J { // NOTE: do not use logging in this class as it interferes with LogManager creation! static final LogAppenderLog4j GLOBAL_APPENDER = new LogAppenderLog4j(LogAppenderLog4j.class.getSimpleName() + "@global", null, null, false); private LogUtilLog4J() { } /** * Check if the default dispatcher factory implementation is the Log4J implementation. * @return true, if the Log4J implementation is used */ public static boolean isDefaultImplementation() { return LogUtil.getGlobalDispatcher() instanceof LogAppenderLog4j.LogEntryDispatcherLog4J; } /** * Translates a Log4J Level object to a custom LogLevel object. *

* This method takes a Log4J Level object as parameter and returns the corresponding custom LogLevel object. * The translation is based on the integer level value of the Log4J Level object. * * @param level the Log4J Level object to be translated * @return the custom LogLevel object that corresponds to the given Log4J Level object */ public static LogLevel translate(Level level) { int levelInt = level.intLevel(); if (levelInt > StandardLevel.DEBUG.intLevel()) { return LogLevel.TRACE; } if (levelInt > StandardLevel.INFO.intLevel()) { return LogLevel.DEBUG; } if (levelInt > StandardLevel.WARN.intLevel()) { return LogLevel.INFO; } if (levelInt > StandardLevel.ERROR.intLevel()) { return LogLevel.WARN; } return LogLevel.ERROR; } /** * Translates a {@link LogLevel} object to a Log4J {@link Level} object. *

* This method takes a LogLevel Level object as parameter and returns the corresponding Log4J Level object. * * @param level the LogLevel object to be translated * @return the Log4j Level object that corresponds to the given LogLevel object */ public static Level translate(LogLevel level) { return switch (level) { case TRACE -> Level.TRACE; case DEBUG -> Level.DEBUG; case INFO -> Level.INFO; case WARN -> Level.WARN; case ERROR -> Level.ERROR; }; } /** * Configures the Log4J bridge implementations that are available. * @param rootLevel the root level to set */ public static void init(LogLevel rootLevel) { // configure the JUL bridge setPropertyIfOnClassPath("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); // configure the commons-logging bridge setPropertyIfOnClassPath("org.apache.commons.logging.LogFactory", "org.apache.logging.log4j.jcl.LogFactoryImpl"); // no configuration necessary for SLF4J // set the root logger level Configuration configuration = LoggerContext.getContext(false).getConfiguration(); GLOBAL_APPENDER.start(); configuration.addAppender(GLOBAL_APPENDER); LoggerConfig rootLogger = configuration.getRootLogger(); rootLogger.addAppender(GLOBAL_APPENDER, null, null); rootLogger.setLevel(translate(rootLevel)); LogUtil.assureInitialized(); } /** * Updates all loggers to add the global appender and refresh their configurations. * *

* This method retrieves the current {@link LoggerContext} from {@link LogManager} and iterates through * all available loggers, adding the global appender to each logger. After updating * the loggers with the global appender, it calls the updateLoggers method of the {@link LoggerContext} * to apply the changes. * *

* This method ensures that all loggers in the application are configured with * the globally defined appender, which might be necessary for consistent logging * behavior across different parts of the application. */ public static void updateLoggers() { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); ctx.getLoggers().forEach(logger -> logger.addAppender(GLOBAL_APPENDER)); ctx.updateLoggers(); } private static void setPropertyIfOnClassPath(String propertyName, String className) { if (isClassOnClasspath(className)) { System.setProperty(propertyName, className); } } /** * Check if a class is on the classpath without loading it. * * @param className the fully qualified name of the class * @return true, if the class is on the classpath */ // DO NOT MOVE TO LANGUTIL OR CALL LANGUTIL METHODS!!! // LANGUTIL INSTANTIATES A LOGGER BUT INITIALISATION MOST BE DONE BEFORE FIRST LOGGER IS INSTANTIATED! public static boolean isClassOnClasspath(String className) { if (!className.matches("^([a-zA-Z_$][a-zA-Z\\d_$]*\\.)*[a-zA-Z_$][a-zA-Z\\d_$]*(\\.[a-zA-Z_$][a-zA-Z\\d_$]*)*$")) { return false; } String classAsResource = className.replace('.', '/') + ".class"; return ClassLoader.getSystemClassLoader().getResource(classAsResource) != null; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy