I currently have a “LocalLogger” Class that handles all my logging stuff. I can make a new Object of that class in my other classes, to maintain the same logging all over.
Currently the LocalLogger Class, makes 2 Log Files. InfoLog and ErrorLog.
My Problem is, that the Logger is writing every Log from different Classes in 1 Log File. That is in general not a problem, and it is the way i want it. BUT he is writing it in the wrong File.
This is my Logger Class:
public class LocalLogger {
private final Logger logger;
private final Logger elogger;
private final Logger ilogger;
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);
elogger = LogManager.getLogger("errorLogger");
ilogger = LogManager.getLogger("infoLogger");
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);
elogger = LogManager.getLogger("errorLogger");
ilogger = LogManager.getLogger("infoLogger");
logInfo("Starting Time: " + new SimpleDateFormat("dd.MM.yyyy - hh:mm:ss").format(startTime));
}
private void configureLogger() {
String infoLog = config != null && config.getLogFile() != null && !config.getLogFile().isEmpty() ? config.getLogFile() : logClass.getSimpleName() + "-INFO.log";
String errorLog = config != null && config.getErrorLogFile() != null && !config.getLogFile().isEmpty() ? config.getErrorLogFile() : logClass.getSimpleName() + "-ERROR.log";
String logLevel = config != null && config.getLogLevel() != null && !config.getLogLevel().isEmpty() ? config.getLogLevel() : "INFO";
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.TRACE));
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(Level.ERROR);
rootLogger.add(builder.newAppenderRef("Console"));
builder.add(rootLogger);
LoggerComponentBuilder errorLogger = builder.newLogger("errorLogger", Level.WARN);
errorLogger.add(builder.newAppenderRef("ErrorFile"));
builder.add(errorLogger);
LoggerComponentBuilder infoLogger = builder.newLogger("infoLogger", Level.TRACE);
infoLogger.add(builder.newAppenderRef("InfoFile"));
builder.add(infoLogger);
LoggerContext ctx = Configurator.initialize(builder.build());
}
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logTrace(String message) {
ilogger.trace(message);
} // trace
/**
* Redirection to Log4j Logger.
*
* @param message message to log
*/
public void logDebug(String message) {
ilogger.debug(message);
} // debug
/**
* 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 logError(String message) {
elogger.error(message);
} // error
/**
* 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);
} // fatal
}
This is a Constructor of one of my other classes:
public Exporter(File adminConfig, String jsonString, Date startTime) {
this.startTime = startTime;
JSONToConfigXML configBuilder = new JSONToConfigXML(jsonString, adminConfig);
File completeConfig = configBuilder.parse();
XMLParser parser = new XMLParser();
Map<String, Object> configMap = parser.parse(completeConfig);
ExportConfiguration cfg = new ExportConfiguration();
cfg.setConfigFile(completeConfig.getAbsolutePath());
initConfig(cfg, configMap);
this.config = cfg;
this.logger = new LocalLogger(this.config, Exporter.class);
}
This is just the simple execute main class:
private static final LocalLogger logger = new LocalLogger(ExporterMain.class);
private static final Date startTime = new Date();
/**
* @param args - Config File
*/
public static void main(String[] args) {
try {
if (args.length < 1) {
System.out.println("Usage: java ExporterMain <filename>");
System.exit(1);
} else {
File config = new File(args[0]);
Exporter exp = new Exporter(config, startTime);
exp.execute();
System.out.println("SuccessCounter: "+ exp.getSuccessCounter());
System.out.println("ErrorCounter: "+ exp.getErrorCounter());
System.out.println("LastItem: "+ exp.getLastItem());
}
} catch (Exception e) {
logger.logSevere("exec", e.getMessage(), e);
System.exit(1);
}
}
Currently he writes 6 Log Files: 2 for ExporterMain, 2 for XMLParser and 2 for Exporter.
Atm he is writing every log in the ExporterMain Log Files. But in this case i want to have all Logs written to the Exporter Log, because there is a log-path in the config which i want to use.
He is creating the File in the right directory from the path in the config, but the files are empty.
6
You can take an approach similar to this – provide a default configuration (you can use a config file (log4j2.xml etc.) for this, or programmatic as follows) that is initialized once only that will do logging for any loggers that you do not provide a config file for. Then, on demand, create new loggers and update the context as needed (when you want to create loggers with some user defined property.
public class misc {
private final Logger logger;
private final Logger elogger;
private final Logger ilogger;
static {
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());
}
public misc() {
logger = LogManager.getLogger(this);
elogger = LogManager.getLogger("errorLogger");
ilogger = LogManager.getLogger("infoLogger");
}
public misc(String configInfo, String configError) {
configureAndAppendLogger(configInfo, configError);
logger = LogManager.getLogger(this);
elogger = LogManager.getLogger(configError);
ilogger = LogManager.getLogger(configInfo);
}
private synchronized void configureAndAppendLogger(String infoLog, String errorLog) {
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
// var loggers = config.getLoggers();
Layout layout = PatternLayout.newBuilder().withPattern("%d [%t] %-5level: %msg%n%throwable").build();
Appender infoAppender = FileAppender.newBuilder().withName(infoLog).withFileName("./csv/"+infoLog).withAppend(true)
.setConfiguration(config).setLayout(layout).build();
AppenderRef infoRef = AppenderRef.createAppenderRef("File", null, null);
AppenderRef[] infoRefs = new AppenderRef[] {infoRef};
infoAppender.start();
config.addAppender(infoAppender);
var newInfoLogger = LoggerConfig.newBuilder().withLoggerName(infoLog).withConfig(config)
.withAdditivity(true).withLevel(Level.valueOf("info")).withIncludeLocation("true")
.withProperties(null).withRefs(infoRefs).withtFilter(null).build();
newInfoLogger.addAppender(infoAppender, null, null);
config.addLogger(infoLog, newInfoLogger);
Appender errorAppender = FileAppender.newBuilder().withName(errorLog).withFileName("./csv/"+errorLog).withAppend(true)
.setConfiguration(config).setLayout(layout).build();
AppenderRef errorRef = AppenderRef.createAppenderRef("File", null, null);
AppenderRef[] errorRefs = new AppenderRef[] {errorRef};
errorAppender.start();
config.addAppender(errorAppender);
var newErrorLogger = LoggerConfig.newBuilder().withLoggerName(errorLog).withConfig(config)
.withAdditivity(true).withLevel(Level.valueOf("warn")).withIncludeLocation("true")
.withProperties(null).withRefs(errorRefs).withtFilter(null).build();
newErrorLogger.addAppender(errorAppender, null, null);
config.addLogger(errorLog, newErrorLogger);
ctx.updateLoggers();
}
/**
* 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
}
This does not avoid the problem of having multiple log files, but will at least separate the logging to the correct log files. I tested it as follows:
public class Main {
// private static final misc m = new misc();
// static {
// m.logInfo("static info");
// m.logWarning("static warning");
// }
public static void main(String[] args) {
misc misc = new misc("testInfo.log", "testErr.log");
misc.logFine("fine");
misc.logInfo("info");
misc.logWarning("warning");
misc misc2 = new misc("secondInfo.log", "secondErr.log");
misc2.logFine("fine");
misc2.logInfo("info");
misc2.logWarning("warning");
}
}
but for some reason even though no logging was done to the default log files, it will still create the log files but will be empty.