This article is the 5th day of Recruit Lifestyle Advent Calendar 2017. I am a loose engineer at Hot Pepper Beauty. It's a shame.
Let's write about dynamic Logger generation under the title of Programmable Logger Generation with logback. </ strong> Well, it's a small logback story that doesn't seem to be in the documentation.
Normally, when using logback, I think that the following logback.xml is prepared.
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
<appender name="APP"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/app.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>14</maxHistory>
</rollingPolicy>
<encoder>
<pattern>time:%d{yyyy-MMM-dd HH:mm:ss.SSS} level:%level marker:%marker thread:%thread logger:%logger file:%file line:%line message:%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="APP" />
</root>
</configuration>
However, there were cases where this XML notation was a problem. Specifically, it was at the time of this job.
What I wanted to do was dynamically set the log file PATH </ strong>. What does that mean ...
/tmp/host1/app-yyyyMMdd.log
./tmp/hostN/app-yyyyMMdd.log
.That is. Well, I don't want to maintain xml as the number of transferred hosts increases or decreases.
I think there are various ways (including not using logback), but this time I tried using logback to programmatically generate Logger </ strong>.
Below is the code of the operation sample. I will also give it to github. https://github.com/shase/logback-dynamic-logger-sample
Main.java
import java.util.stream.Stream;
import ch.qos.logback.classic.Logger;
public class Main {
public static void main(String...args) {
//Imagine that the host name comes in from the outside here.
String[] path = {"/tmp/host1/app-%d{yyyyMMdd}.log","/tmp/host2/app-%d{yyyyMMdd}.log","/tmp/host3/app-%d{yyyyMMdd}.log"};
Stream.of(path)
.forEach(p -> {
Logger logger = new SimpleLoggerFactory().getLogger("sample", p);
logger.info("dynamic path");
});
}
}
SimpleLoggerFactory.java
import java.nio.charset.StandardCharsets;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
public class SimpleLoggerFactory {
public Logger getLogger(String loggerName, String path) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern("%msg%n");
ple.setContext(lc);
ple.setCharset(StandardCharsets.UTF_8);
ple.start();
RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<>();
TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new TimeBasedRollingPolicy<>();
rollingPolicy.setFileNamePattern(path);
rollingPolicy.setMaxHistory(14);
rollingPolicy.setParent(fileAppender);
rollingPolicy.setContext(lc);
rollingPolicy.start();
fileAppender.setAppend(true);
fileAppender.setEncoder(ple);
fileAppender.setRollingPolicy(rollingPolicy);
fileAppender.setContext(lc);
fileAppender.start();
Logger logger = (Logger) LoggerFactory.getLogger(loggerName);
logger.addAppender(fileAppender);
logger.setAdditive(false);
return logger;
}
}