im currently trying to create a LocalLogger Class which i can use in my Project to log stuff.
General Idea is:
Logs from TRACE to INFO -> infoLog.log Logs from WARN to FATAL -> errorLog.log ALL LOGS IN CONSOLE
I want to set the info and error Log Path dynamically from a Config Class in my Project. Thats why i wanted to use the programmatically provided configuration.
I tried out stuff, but currently all i get are FATAL logs, in console and both log files. No matter what i do.
So basically the structure is like this:
public class LocalLogger {
private final Logger logger;
private final Class<?> logClass;
private Configuration config;
private final Date startTime;
public LocalLogger(Configuration config, Class<?> logClass) {
this.config = config;
this.logClass = logClass;
this.startTime = new Date();
configureLogger();
logger = LogManager.getLogger(logClass);
logInfo("Starting Time: " + new SimpleDateFormat("dd.MM.yyyy - hh:mm:ss").format(startTime));
logInfo("ErrorLogFile set to -> " + config.getErrorLogFile());
}
public LocalLogger(Class<?> logClass) {
this.logClass = logClass;
this.startTime = new Date();
configureLogger();
logger = LogManager.getLogger(logClass);
logInfo("Starting Time: " + new SimpleDateFormat("dd.MM.yyyy - hh:mm:ss").format(startTime));
}
/***
* Sets Logging to configured LogFile/ErrorLogFile and LogLevel in xml-configurationFile
*/
private void configureLogger() {
/* this is the magic part, where i need help (when config is not set / null -> just use "infoLog.log" and "errorLog.log" */
}
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logInfo(String message) {
logger.info(message);
} // info
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logWarning(String message) {
logger.warn(message);
} // warn
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFine(String message) {
logger.debug(message);
} // debug
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFinest(String message) {
logger.trace(message);
} // debug
/**
* Handles truncated stack trace logging via Log4j Logging
*
* @param key unique String value (e.g. file path)
* @param message individual log message
* @param exception the exception to log with max stack trace length
*
*/
public void logSevere(String key, String message, Exception exception) {
//TODO special exception Handling?
String msg = key + ":" + message;
logger.fatal(msg);
} // error
I tried it like that:
private void configureLogger() {
String infoLog = config != null && config.getLogFile() != null && config.getLogFile().isEmpty() ? config.getLogFile() : "infoLog.log";
String errorLog = config != null && config.getErrorLogFile() != null && config.getErrorLogFile().isEmpty() ? config.getErrorLogFile() : "errorLog.log";
String logLevel = config != null && config.getLogLevel() != null && config.getLogLevel().isEmpty() ? config.getLogLevel() : "TRACE";
try (LoggerContext context = (LoggerContext) LogManager.getContext(true)) {
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(org.apache.logging.log4j.Level.WARN);
builder.setConfigurationName("DynamicConfig");
AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "CONSOLE")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
consoleAppender.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
builder.add(consoleAppender);
AppenderComponentBuilder fileInfoAppender = builder.newAppender("InfoFile", "FILE")
.addAttribute("fileName", infoLog)
.addAttribute("append", "true");
fileInfoAppender.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
fileInfoAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.INFO));
builder.add(fileInfoAppender);
AppenderComponentBuilder fileErrorAppender = builder.newAppender("ErrorFile", "FILE")
.addAttribute("fileName", errorLog)
.addAttribute("append", "true");
fileErrorAppender.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
fileErrorAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.WARN));
builder.add(fileErrorAppender);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(org.apache.logging.log4j.Level.getLevel(logLevel));
rootLogger.add(builder.newAppenderRef("Console"));
rootLogger.add(builder.newAppenderRef("InfoFile"));
rootLogger.add(builder.newAppenderRef("ErrorFile"));
builder.add(rootLogger);
org.apache.logging.log4j.core.config.Configuration configuration = builder.build();
context.start(configuration);
}
}
Test Class was this:
public class TestingMain {
public static void main(String[] args) {
LocalLogger logger = new LocalLogger(TestingMain.class);
logger.logInfo("Test");
logger.logSevere("Test", "123", new Exception());
}
}
OUTPUT:
2024-08-28T08:31:57.614119700Z main WARN No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2
10:31:57.640 [main] FATAL de.tde.ecm.vp.fp8.start.TestingMain - Test:123
Ok, so I went through your configuration and went through the log4j wiki since yesterday. The root cause is that when using a ConfigurationBuilder, you need to initialize the builder using the Configurator.initialize
methods otherwise a default configuration is used for logging.
public class misc {
private final Logger logger;
public misc() {
configureLogger();
logger = LogManager.getLogger(this);
}
public static void main(String[] args) {
misc m = new misc();
m.logFine("fine");
m.logInfo("info");
m.logWarning("warning");
}
private void configureLogger() {
String infoLog = "infoLog.log";
String errorLog = "errorLog.log";
String logLevel = "TRACE";
try (LoggerContext context = (LoggerContext) LogManager.getContext(true)) {
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(org.apache.logging.log4j.Level.WARN);
builder.setConfigurationName("DynamicConfig");
LayoutComponentBuilder standard
= builder.newLayout("PatternLayout");
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");
AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "Console")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
consoleAppender.add(standard);
builder.add(consoleAppender);
AppenderComponentBuilder fileInfoAppender = builder.newAppender("InfoFile", "File")
.addAttribute("fileName", infoLog)
.addAttribute("append", "true");
fileInfoAppender.add(standard);
fileInfoAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.INFO));
builder.add(fileInfoAppender);
AppenderComponentBuilder fileErrorAppender = builder.newAppender("ErrorFile", "File")
.addAttribute("fileName", errorLog)
.addAttribute("append", "true");
fileErrorAppender.add(standard);
fileErrorAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.WARN));
builder.add(fileErrorAppender);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(org.apache.logging.log4j.Level.getLevel(logLevel));
rootLogger.add(builder.newAppenderRef("Console"));
rootLogger.add(builder.newAppenderRef("InfoFile"));
rootLogger.add(builder.newAppenderRef("ErrorFile"));
builder.add(rootLogger);
var ctx = Configurator.initialize(builder.build()); // <--
// org.apache.logging.log4j.core.config.Configuration configuration = builder.build();
// context.start(configuration);
}
}
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logInfo(String message) {
logger.info(message);
} // info
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logWarning(String message) {
logger.warn(message);
} // warn
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFine(String message) {
logger.debug(message);
} // debug
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFinest(String message) {
logger.trace(message);
} // debug
/**
* Handles truncated stack trace logging via Log4j Logging
*
* @param key unique String value (e.g. file path)
* @param message individual log message
* @param exception the exception to log with max stack trace length
*
*/
public void logSevere(String key, String message, Exception exception) {
//TODO special exception Handling?
String msg = key + ":" + message;
logger.fatal(msg);
} // error
}
Also, while perusing the Log4j2 wiki, it seems the try-with resources wasn't really used, so at the end of the day, I removed it to end up with the following:
private void configureLogger() {
String infoLog = "infoLog.log";
String errorLog = "errorLog.log";
String logLevel = "TRACE";
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(org.apache.logging.log4j.Level.WARN);
builder.setConfigurationName("DynamicConfig");
LayoutComponentBuilder standard
= builder.newLayout("PatternLayout");
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");
AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "Console")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
consoleAppender.add(standard);
builder.add(consoleAppender);
AppenderComponentBuilder fileInfoAppender = builder.newAppender("InfoFile", "File")
.addAttribute("fileName", infoLog)
.addAttribute("append", "true");
fileInfoAppender.add(standard);
fileInfoAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.INFO));
builder.add(fileInfoAppender);
AppenderComponentBuilder fileErrorAppender = builder.newAppender("ErrorFile", "File")
.addAttribute("fileName", errorLog)
.addAttribute("append", "true");
fileErrorAppender.add(standard);
fileErrorAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.WARN));
builder.add(fileErrorAppender);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(org.apache.logging.log4j.Level.getLevel(logLevel));
rootLogger.add(builder.newAppenderRef("Console"));
rootLogger.add(builder.newAppenderRef("InfoFile"));
rootLogger.add(builder.newAppenderRef("ErrorFile"));
builder.add(rootLogger);
var ctx = Configurator.initialize(builder.build());
}
but, as I mentioned in the comments, your use of rootlogger for everything means that your infoLog.log will look like:
2024-08-29 10:40:51,816 [main] INFO : info
2024-08-29 10:40:51,820 [main] WARN : warning
2024-08-29 10:42:16,552 [main] INFO : info
2024-08-29 10:42:16,554 [main] WARN : warning
2024-08-29 10:43:04,961 [main] INFO : info
2024-08-29 10:43:04,963 [main] WARN : warning
2024-08-29 10:43:52,780 [main] INFO : info
2024-08-29 10:43:52,782 [main] WARN : warning
2024-08-29 10:54:20,617 [main] INFO : info
2024-08-29 10:54:20,619 [main] WARN : warning
Then, you need to configure new loggers for your specific purposes like so:
private final Logger logger;
private final Logger elogger;
private final Logger ilogger;
public misc() {
configureLogger();
logger = LogManager.getLogger(this);
elogger = LogManager.getLogger("errorLogger");
ilogger = LogManager.getLogger("infoLogger");
}
public static void main(String[] args) {
misc m = new misc();
m.logFine("fine");
m.logInfo("info");
m.logWarning("warning");
}
private void configureLogger() {
String infoLog = "infoLog.log";
String errorLog = "errorLog.log";
String logLevel = "TRACE";
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(org.apache.logging.log4j.Level.WARN);
builder.setConfigurationName("DynamicConfig");
LayoutComponentBuilder standard
= builder.newLayout("PatternLayout");
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");
AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "Console")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
consoleAppender.add(standard);
builder.add(consoleAppender);
AppenderComponentBuilder fileInfoAppender = builder.newAppender("InfoFile", "File")
.addAttribute("fileName", infoLog)
.addAttribute("append", "true");
fileInfoAppender.add(standard);
fileInfoAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.INFO));
builder.add(fileInfoAppender);
AppenderComponentBuilder fileErrorAppender = builder.newAppender("ErrorFile", "File")
.addAttribute("fileName", errorLog)
.addAttribute("append", "true");
fileErrorAppender.add(standard);
fileErrorAppender.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", org.apache.logging.log4j.Level.WARN));
builder.add(fileErrorAppender);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(org.apache.logging.log4j.Level.getLevel(logLevel));
rootLogger.add(builder.newAppenderRef("Console"));
builder.add(rootLogger);
var errorLogger = builder.newLogger("errorLogger", Level.WARN);
errorLogger.add(builder.newAppenderRef("ErrorFile"));
builder.add(errorLogger);
var infoLogger = builder.newLogger("infoLogger", Level.INFO);
infoLogger.add(builder.newAppenderRef("InfoFile"));
builder.add(infoLogger);
var ctx = Configurator.initialize(builder.build());
}
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logInfo(String message) {
ilogger.info(message);
} // info
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logWarning(String message) {
elogger.warn(message);
} // warn
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFine(String message) {
logger.debug(message);
} // debug
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logFinest(String message) {
logger.trace(message);
} // debug
/**
* Handles truncated stack trace logging via Log4j Logging
*
* @param key unique String value (e.g. file path)
* @param message individual log message
* @param exception the exception to log with max stack trace length
*
*/
public void logSevere(String key, String message, Exception exception) {
//TODO special exception Handling?
String msg = key + ":" + message;
elogger.fatal(msg);
} // error