Files
Jackfruit/demo/src/main/java/crucible/crust/logging/Log4j2Configurator.java
Hari Nair fa4b36f2f5 1 publish to maven central (#2)
* pom updates

* update artifactId, add gpg plugin

* use oss.sonatype.org

* update groupId in README

* update plugins

* use nexus-staging-maven-plugin

* add javadoc

* javadoc cleanup

* update versioning

* javadoc cleanup

* Update demo

---------

Co-authored-by: Hari Nair <hari@alumni.caltech.edu>
2023-09-05 17:16:54 -04:00

209 lines
6.9 KiB
Java

package crucible.crust.logging;
/*-
* #%L
* jackfruit-demo
* %%
* Copyright (C) 2023 Johns Hopkins University Applied Physics Laboratory
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;
/**
* A simple configuration class.
*
* <p>Default settings:
*
* <ul>
* <li>Pattern is "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%c{1}:%L] %msg%n%throwable"<br>
* (e.g. 2021-11-09 19:32:37.119 INFO [LoggingTest:25] Level INFO)
* <li>Log level is {@link Level#INFO}
* </ul>
*
* @author Hari.Nair@jhuapl.edu
*/
public class Log4j2Configurator {
private PatternLayout layout;
private final Map<String, FileAppender> fileAppenders;
private static Log4j2Configurator instance = null;
/**
* @return an instance of this singleton class.
*/
public static synchronized Log4j2Configurator getInstance() {
if (instance == null) {
instance = new Log4j2Configurator();
}
return instance;
}
private Log4j2Configurator() {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
layout =
PatternLayout.newBuilder()
.withPattern(DefaultConfiguration.DEFAULT_PATTERN)
.withConfiguration(config)
.build();
fileAppenders = new HashMap<>();
setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%c{1}:%L] %msg%n%throwable");
setLevel(Level.INFO);
}
/**
* @return a map of logger names to {@link LoggerConfig}
*/
private Map<String, LoggerConfig> getLoggerMap() {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
Map<String, LoggerConfig> loggerMap = new HashMap<>(config.getLoggers());
loggerMap.put(
LogManager.getRootLogger().getName(),
config.getLoggerConfig(LogManager.getRootLogger().getName()));
return Collections.unmodifiableMap(loggerMap);
}
/**
* @param filename Append log to named file, or create it if it doesn't exist.
*/
public void addFile(String filename) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
Map<String, LoggerConfig> loggerMap = getLoggerMap();
FileAppender appender =
FileAppender.newBuilder()
.setName(filename)
.withFileName(filename)
.setLayout(layout)
.build();
appender.start();
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
loggerConfig.addAppender(appender, null, null);
}
loggerContext.updateLoggers();
fileAppenders.put(filename, appender);
}
/**
* @param filename Stop logging to named file.
*/
public void removeFile(String filename) {
if (fileAppenders.containsKey(filename)) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
Map<String, LoggerConfig> loggerMap = getLoggerMap();
FileAppender appender = fileAppenders.get(filename);
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
loggerConfig.removeAppender(appender.getName());
}
loggerContext.updateLoggers();
fileAppenders.remove(filename);
}
}
/**
* @param pattern layout pattern for all {@link ConsoleAppender} and {@link FileAppender} objects.
*/
public void setPattern(String pattern) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
layout = PatternLayout.newBuilder().withConfiguration(config).withPattern(pattern).build();
Map<String, LoggerConfig> loggerMap = getLoggerMap();
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
Map<String, Appender> appenderMap = loggerConfig.getAppenders();
for (String appenderName : appenderMap.keySet()) {
Appender newAppender = null;
Appender oldAppender = appenderMap.get(appenderName);
// there should be a better way to do this - a toBuilder() method on the appender would be
// really useful
if (oldAppender instanceof ConsoleAppender) {
newAppender =
ConsoleAppender.newBuilder()
.setName(appenderName)
.setConfiguration(config)
.setLayout(layout)
.build();
} else if (oldAppender instanceof FileAppender) {
newAppender =
FileAppender.newBuilder()
.setName(appenderName)
.setConfiguration(config)
.withFileName(((FileAppender) oldAppender).getFileName())
.setLayout(layout)
.build();
}
if (newAppender != null) {
newAppender.start();
loggerConfig.removeAppender(appenderName);
loggerConfig.addAppender(newAppender, null, null);
}
}
}
loggerContext.updateLoggers();
}
/**
* Sets the levels of <code>parentLogger</code> and all 'child' loggers to the given <code>level
* </code>. This is simply a call to
*
* <pre>
* Configurator.setAllLevels(parentLogger, level)
* </pre>
*
* @param parentLogger name of parent logger
* @param level logging level
*/
public void setLevel(String parentLogger, Level level) {
Configurator.setAllLevels(parentLogger, level);
}
/**
* Set all logger levels. This is simply a call to
*
* <pre>
* setLevel(LogManager.getRootLogger().getName(), level)
* </pre>
*
* @param level logging level
*/
public void setLevel(Level level) {
setLevel(LogManager.getRootLogger().getName(), level);
}
}