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;
	}
}