Log4jConfigurator.java

package com.reallifedeveloper.common.infrastructure.jmx;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

import com.reallifedeveloper.common.domain.ErrorHandling;

/**
 * An implementation of the JMX {@link LogConfiguratorMXBean} interface using Log4j.
 *
 * @author RealLifeDeveloper
 */
@ManagedResource(description = "Log4j Configuration")
public class Log4jConfigurator implements LogConfiguratorMXBean {

    @Override
    @ManagedAttribute(description = "The available loggers")
    public List<String> getLoggers() {
        List<String> configLoggers = getContext().getConfiguration().getLoggers().entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue().getLevel()).toList();
        List<String> contextLoggers = getContext().getLoggers().stream().map(l -> l.getName() + "=" + l.getLevel()).toList();
        return Stream.concat(configLoggers.stream(), contextLoggers.stream()).distinct().toList();
    }

    @Override
    @ManagedOperation(description = "Gives the log level for a logger")
    @ManagedOperationParameters({ @ManagedOperationParameter(name = "logger", description = "The name of the logger") })
    public String getLogLevel(String loggerName) {
        return getLoggerIfExists(loggerName).map(l -> l.getLevel().name()).orElse("unavailable");
    }

    @Override
    @ManagedOperation(description = "Sets the log level for a logger")
    @ManagedOperationParameters({ @ManagedOperationParameter(name = "logger", description = "The name of the logger"),
            @ManagedOperationParameter(name = "level", description = "The new log level") })
    public void setLogLevel(String loggerName, String level) {
        if (isNotBlank(loggerName) && isNotBlank(level)) {
            Level logLevel = Level.getLevel(level);
            if (logLevel != null) {
                Logger logger = getOrCreateLogger(loggerName);
                logger.setLevel(logLevel);
            }
        }
    }

    @SuppressWarnings("PMD.CloseResource") // Closing the LoggerContext shuts down logging.
    private static Optional<Logger> getLoggerIfExists(String loggerName) {
        ErrorHandling.checkNull("loggerName must not be null", loggerName);
        LoggerContext context = getContext();
        if (context.hasLogger(loggerName) || context.getConfiguration().getLoggers().containsKey(loggerName)) {
            return Optional.of(context.getLogger(loggerName));
        } else {
            return Optional.empty();
        }
    }

    private static Logger getOrCreateLogger(String loggerName) {
        return getContext().getLogger(loggerName);
    }

    private static LoggerContext getContext() {
        return LoggerContext.getContext();
    }

    private static boolean isNotBlank(String s) {
        return s != null && !s.isBlank();
    }
}