Logback
Logback์์์ ์ค์
Logback configuration ์ค๋ช ์ ์์, Joran์ด๋ผ๋ ์ด๋ฆ์ด ์์ฃผ ๋์ฌ ๊ฒ์ ๋๋ค. Joran์ Logback์ด ์ฌ์ฉํ๋ configuration ํ๋ ์์ํฌ์ ๋๋ค.
๋ํ, ์ค๊ฐ ์ ๋์ ํฌ๊ธฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ผ๋ ์ฝ๋์ ์์ฒ ๊ฐ์ ๋ก๊น ๋ฌธ์ ํฌํจํ๊ธฐ์ ๊ทธ๊ฒ๋ค์ ํจ์จ์ ์ด๊ณ ๊ฐํธํ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋๊ตฌ๊ฐ ํ์ํ์ต๋๋ค.
Logback์ ํ๋ก๊ทธ๋๋ฐ์ผ๋ก ๋๋ XML์ด๋ Groovy ํฌ๋งท์ ์ค์ ์คํฌ๋ฆฝํธ ํ์ผ์ ํตํด์ ์ค์ ํ ์ ์์ต๋๋ค. Logback์ด ์ค์ค๋ก ์ค์ ์ ์ฐพ๋ ์คํ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
classpath์์ logback-test.xml ํ์ผ์ ์ฐพ์ต๋๋ค.
(1) ๊ณผ์ ์์ ํ์ผ์ ์ฐพ์ง ๋ชปํ๋ค๋ฉด, classpath์์ logback.groovy ํ์ผ์ ์ฐพ์ต๋๋ค.
(2) ๊ณผ์ ์์ ํ์ผ์ ์ฐพ์ง ๋ชปํ๋ค๋ฉด, classpath์์ logback.xml ํ์ผ์ ์ฐพ์ต๋๋ค.
(3) ๊ณผ์ ์์ ํ์ผ์ ์ฐพ์ง ๋ชปํ๋ค๋ฉด, JDK 1.6์ service-provider loading facility (Service Loader)์ ์ํด com.qos.logback.classic.spi.Configurator ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ์ฐพ์ต๋๋ค. ํ์ ์์น๋ classpath์์ META-INF\services\ch.qos.logback.classic.spi.Configurator ์
๋๋ค.
์ ๊ณผ์ ์์ ์ฑ๊ณตํ ๊ฒฝ์ฐ๊ฐ ์๋ค๋ฉด, logback์ ์ฝ์์ ์ถ๋ ฅํ๋ BasicConfigurator์ผ๋ก ์ค์ ํฉ๋๋ค.
๋น์ ์ด ํน๋ณํ Logback ์ค์ ์ ํ์ง ์์ ๊ฒ์ด๋ผ๋ฉด ์๋์ผ๋ก (5) ๋ฒ์ BasicConfigurator๋ก ์ค์ ๋ ๊ฒ์ ๋๋ค. ํ์ง๋ง, Joran์ด Logback Conguration ํ์ผ์ ํ์ฑ ํ๋๋ฐ 100 ๋ฐ๋ฆฌ์ธ์ปจ๋ ์ ๋์ ์๊ฐ์ด ์์๋ฉ๋๋ค. ์ด ์ ๋์ ๋ช ๋ฐ๋ฆฌ์ธ์ปจ๋๋ผ๋ ์ค์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ๋น ๋ฅด๊ฒ ์์๋๊ธธ ๋ฐ๋๋ค๋ฉด (1) ~ (4) ์คํ ์ ์๋ตํ ์ ์๋๋ก ์ง์ BasicConfigurator๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
Logback ์๋ ์ค์
logback์ ์ค์ ํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๊ทธ๋ฅ ์๋ฌด ์ค์ ์ ์์ด BasicConfigurator์๊ฒ ๋งก๊ธฐ๋ ๊ฒ์ ๋๋ค. ์ด๋ ๊ฒ ์ง์ ํ ๊ฒฝ์ฐ console์ ๋ก๊ทธ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋จ์ ํ์ธํ ์ ์์ต๋๋ค. BasicConfigurator๋ฅผ ํตํด ์ค์ ํ ๊ฒฝ์ฐ ์ต์ํ์ผ๋ก ์ค์ ๋ ConsoleAppender๊ฐ ๋ฃจํธ ๋ก๊ฑฐ์ ๋ถ์ฐฉ๋๊ฒ ๋ฉ๋๋ค. ์ถ๋ ฅ ํฌ๋งท์ ์๋์ ๊ฐ์ด ์ง์ ๋์์ผ๋ฉฐ PatternLayoutEncoder์ ๋ฑ๋ก๋์ด์๊ณ , ๋ฃจํธ ๋ก๊ฑฐ์ ๋ ๋ฒจ์ DEBUG๋ก ์ง์ ๋ฉ๋๋ค.
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n.
์์)
package chapters.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Foo {
static final Logger logger = LoggerFactory.getLogger(Foo.class);
public void doIt() {
logger.debug("Did it again!");
}
}
16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again!
logback-test.xml / logback.xml์ ์ด์ฉํ Logback ์๋ ์ค์
์์ ์ค์ ๊ณผ์ ์์ ์์๋ณด์๋ค์ํผ, Logback์ ์ค์ ํ์ผ์ ์ฐพ๋ ์์๊ฐ ์กด์ฌํฉ๋๋ค. ์ด๋ฒ์๋ classpath์ logback.xml ํ์ผ์ ์์ฑํ๊ณ ์๋์ ๊ฐ์ด Logback ์ค์ ์ ์์ฑํด๋ด ์๋ค. ์๋์ ์ค์ ์ BasicConfigurator์ ๋์ผํ ์ค์ ์ ๋๋ค. ์ดํ ๋์์์ผ๋ณด๋ฉด ์์ ๊ฒฐ๊ณผ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์์ ํ์ธํ ์ ์์ต๋๋ค.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Configuration ํ์ผ์ ๋ถ์ํ๋ ๋์ ๊ฒฝ๊ณ ๋๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด, Logback์ ๋ด์ฅ ์ํ ์์คํ ์ ์ํด ์ฝ์์ ๋ด๋ถ ์ํ ๋ฐ์ดํฐ(Status Data)๋ฅผ ์๋์ผ๋ก ์ถ๋ ฅํฉ๋๋ค. ๋ง์ฝ ์ฌ์ฉ์๊ฐ ์ํ ์์ ์ฝ๋๋ฅผ ๋ช ์์ ์ผ๋ก ๋ฑ๋กํ ๊ฒฝ์ฐ ์ค๋ณต์ ์ ๊ฑฐํ๊ธฐ ์ํด Logback์ ์๋ ์ํ ์ถ๋ ฅ ๊ธฐ๋ฅ์ ๋นํ์ฑํ๋ฉ๋๋ค.
์ํ ๋ฐ์ดํฐ๋ StatusPrinter๋ฅผ ์ด์ฉํ์ฌ ์ถ๋ ฅํ๋ ๋ฐฉ๋ฒ์ด ์๋ ๋ฐ๋ฉด, logback.xml ํ์ผ์ ํตํด ์ค์ ํ ์ ์์ต๋๋ค. ๋ฐฉ๋ฒ์ configuration๋๋ ํฐ๋ธ์ debug="true" ์์ฑ์ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
<configuration debug="true"> <!-- ์ํ ๋ฐ์ดํฐ ์ถ๋ ฅ -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ StatusListener๋ฅผ ๋ฑ๋กํ๋ ๊ฒ์ ๋๋ค. debug="true" ์์ฑ์ OnConsoleStatusListener๋ฅผ ๋ฑ๋กํ๋ ๊ฒ๊ณผ ์์ ํ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค.
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
... the rest of the configuration file
</configuration>
์์คํ
๋ณ์๋ฅผ ํตํ Logback Configuration ๊ฒฝ๋ก ์ง์
Logback์ด ์คํ ์ ๋ฐ๋ผ ์ค์ ์ ์ฐพ๋ ๋ฐฉ๋ฒ ์ด์ธ logback.configuration ์ด๋ฆ์ ์์คํ ๋ณ์๋ก ๊ฒฝ๋ก๋ฅผ ์ง์ ํด์ค ์ ์์ต๋๋ค. ๊ฒฝ๋ก์ logback ์ค์ ํ์ผ์ ํ์ฅ์๋ ํญ์ ".xml" ํน์ ".groovy"์ด์ด์ผ๋ง ํฉ๋๋ค. ์ด ์์คํ ์ค์ ์ java ์คํ command ์ต์ ์ผ๋ก ์ง์ ํ ์ ์์ผ๋ฉฐ ๋ํ Application Code์์ ์ถ๊ฐํด ์ค ์ ์์ต๋๋ค.
java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1
import ch.qos.logback.classic.util.ContextInitializer;
public class ServerMain {
public static void main(String args[]) throws IOException, InterruptedException {
// must be set before the first call to LoggerFactory.getLogger();
// ContextInitializer.CONFIG_FILE_PROPERTY is set to "logback.configurationFile"
System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, "/path/to/config.xml");
...
}
}
์๋ Configuration ์ฌ๊ตฌ์ฑ
logback-classic ๋ชจ๋์ ์ฃผ๊ธฐ์ ์ผ๋ก configuration ํ์ผ์ ์ฝ์ด Logback์ ์ค์ ์ ์ฌ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์ด๋ Application์ด ๋์ ์ค์ผ ๋ ์ฌ์์ ์์ด ์ค์ ํ์ผ์ ์์ ํ๊ณ ์ ์ฉํ ์ ์๋ ์ฅ์ ์ด ์์ต๋๋ค. ์๋์ผ๋ก Logback ์ค์ ์ฌ๊ตฌ์ฑ์ ์ํด configuration ๋๋ ํฐ๋ธ์ scan="true" ์์ฑ์ ์ถ๊ฐํฉ๋๋ค. ๊ธฐ๋ณธ์ผ๋ก ์ ์ฉ๋๋ scan ์ฃผ๊ธฐ๋ 1๋ถ์ ๋๋ค. scan์ฃผ๊ธฐ๋ scanPeriod ์์ฑ์ ์ด์ฉํ์ฌ ์ง์ ํด์ค ์ ์์ต๋๋ค.
<configuration scan="true" scanPeriod="30 seconds" >
...
</configuration>
scanPeriod์ ๊ฐ์ ์๊ฐ๊ณผ ์๊ฐ์ ๋จ์("milliseconds", "seconds", "minutes", "hours")๋ฅผ ์กฐํฉํ์ฌ ๊ธฐ์ ํฉ๋๋ค.
ํจํค์ง ๋ฐ์ดํฐ ๋ก๊น
Logback์ ์ด์ฉํ์ฌ ์ฌ์ฉํ๋ ํจํค์ง ๋ฐ์ดํฐ๋ฅผ ๋ก๊น ํ ์ ์์ต๋๋ค. 1.1.4 ๋ฒ์ ์ดํ ์ด ์ค์ ์ ๊ธฐ๋ณธ๊ฐ์ด disable ๋์๊ธฐ ๋๋ฌธ์ ํจํค์ง ๋ฐ์ดํฐ ๋ก๊น ์ ์ํด์๋ configuration ๋๋ ํฐ๋ธ์ packagingData="true" ์์ฑ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ด๋ versioning ์ด์์ ๋ํ ๋ฌธ์ ๋ฅผ ํ์ ํ๋๋ฐ ํฐ ๋์์ด ๋ฉ๋๋ค. ํ์ง๋ง ํจํค์ง ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฌํ๊ณ ๋ก๊น ํ๋ ๊ณผ์ ์ ๋น๊ต์ ํฐ ๋น์ฉ์ ๊ฐ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ๋ฐ๋ผ ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ์ฌ์ผ ํฉ๋๋ค. ์ด ์ค์ ์ LoggerContext์์๋ ์ง์ ๊ฐ๋ฅํฉ๋๋ค.
<configuration packagingData="true">
...
</configuration>
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.setPackagingDataEnabled(true);
JoranConfigurator ์ง์ ์ด์ฉํ๊ธฐ
Logback์ logback-core ๋ชจ๋ ๋ด ์กด์ฌํ๋ Joran์ด๋ผ๋ configuration ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํฉ๋๋ค. ๊ธฐ๋ณธ Configuration ๋ฉ์ปค๋์ฆ์ผ๋ก Logback์ classpath์์ ์ฐพ์ ๊ธฐ๋ณธ configuration ํ์ผ์์ JoranConfigurator๋ฅผ ํธ์ถํฉ๋๋ค. ๋ง์ฝ ์ด๋ ํ ์ด์ ๋ก ๊ธฐ๋ณธ ๋ก๊ทธ๋ฐฑ์ configuration ๋ฉ์ปค๋์ฆ์ ์ค๋ฒ๋ผ์ด๋ํ๊ณ ์ถ๋ค๋ฉด ์ง์ JoranConfigurator๋ฅผ ์ง์ ํธ์ถํ์ฌ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
package chapters.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
public class MyApp3 {
final static Logger logger = LoggerFactory.getLogger(MyApp3.class);
public static void main(String[] args) {
// assume SLF4J is bound to logback in the current environment
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
try {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
// Call context.reset() to clear any previous configuration, e.g. default
// configuration. For multi-step configuration, omit calling context.reset().
context.reset();
configurator.doConfigure(args[0]);
} catch (JoranException je) {
// StatusPrinter will handle this
}
StatusPrinter.printInCaseOfErrorsOrWarnings(context);
logger.info("Entering application.");
Foo foo = new Foo();
foo.doIt();
logger.info("Exiting application.");
}
}
์์ ์ฝ๋๋ฅผ ์ดํด๋ด ์๋ค. ์ฐ์ LoggerContext๋ฅผ ์ง์ ๊ฐ์ ธ์ค๊ณ , JoranConfigurator๋ฅผ ์์ฑํฉ๋๋ค. JoranConfigurator์ context๋ก ์ด์ ์ค์์ ๊ฐ์ ธ์จ LoggerContext๋ฅผ ์ง์ ํฉ๋๋ค. context๋ configuration ํ์ผ์ ์ฝ๊ณ ํ์ฑ ํ๋ ๋์์ ์ํด ์ง์ ํด์ผ ํฉ๋๋ค. ์ดํ, LoggerContext๋ฅผ ์ด๊ธฐํํ๊ณ main ๋ฉ์๋๋ก ์ ๋ฌ๋ฐ์ configuration file ์ด๋ฆ์ ํตํด ์ค์ ํ๋๋ก ํฉ๋๋ค. JoranConfigurator์ context๋ฅผ ์ธํ ํ ํ StatusPrinter๋ฅผ ํตํด ๋ด๋ถ ์ํ ๋ํ ์ถ๋ ฅํ๋๋ก ์ค์ ํ์ฌ ์ฃผ์์ต๋๋ค.
LoggerContext ์ด๊ธฐํ๋ multi-step configuration ๊ณผ์ ์ ์ํด ๋ฐ๋์ ํธ์ถ๋์ด์ผ ํ๋ ๊ณผ์ ์ ๋๋ค.
Logger์ ์ํ ๋ฉ์์ง ํ๋ฉด ์ค์
Logback์ LoggerContext๋ฅผ ํตํด StatusManager๋ผ๋ ๊ฐ์ฒด์ ๋ด๋ถ ์ํ ๋ฐ์ดํฐ๋ค์ ์์งํฉ๋๋ค. Logback์ ์ง์ ๋ default StatusManager๋ ๋ฉ๋ชจ๋ฆฌ ์ ์ธ ์ธก๋ฉด์์ ํ์ํ ์ ๋์ ์๋ง ๊ฐ๋๋ก ํ๊ธฐ ์ํด ๋ (Head์ Tail) ๋ถ๋ถ์ผ๋ก ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ๊ธ์ ๊ทธ๋๋ก Header๋ ๋ก๊ทธ์ ์ฒซ ๋ถ๋ถ์ ์๋ฏธํ๋ฉฐ Tail์ ๋ (์ต์ ) ๋ถ๋ถ์ ์๋ฏธํฉ๋๋ค. Default ์ค์ ๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์งํ ๋ก๊ทธ์ ๊ฐ์๋ 150๊ฐ์ ๋๋ค (์ด๋ ์ถํ release์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค).
logback-classic์์๋ ์ด๋ฌํ ์ํ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํํ์ฌ ๋ณผ ์ ์๋๋ก ViewStatusMessageServlet์ ์ ๊ณตํฉ๋๋ค. ViewStatusMessageServlet์ ํ์ฌ ์ฌ์ฉ ์ค์ธ LoggerContext์ ํด๋นํ๋ StatusManager ๋ด์ฉ๋ค์ HTML ํ ์ด๋ธ๋ก ์ถ๋ ฅํด์ค๋๋ค. ์ฌ์ฉ์ ์ํด WEB-INF/web.xml ํ์ผ์ ViewStatusMessageServlet์ ์ค์ ํ์ฌ์ผ ํฉ๋๋ค.
<servlet>
<servlet-name>ViewStatusMessages</servlet-name>
<servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewStatusMessages</servlet-name>
<url-pattern>/lbClassicStatus</url-pattern>
</servlet-mapping>
ViewStatusMessage ์๋ธ๋ฆฟ์ ๋์์ ํ์ธํ๊ธฐ ์ํด์ http://{host}/lbClassicStatus ๋ก ์ ์ํฉ๋๋ค. (host๋ ๋์ํ Application์ host ์ฃผ์๋ก ์ ๋ ฅํฉ๋๋ค). \

์ํ ๋ฉ์์ง ๋ฆฌ์ค๋
StatutManager์ StatusListener๋ฅผ ๋ถ์ฌ ์ํ ๋ฉ์์ง์ ๋ํ ์๋ต์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. Logback์ StatusListener์ ๊ตฌํ์ฒด๋ก ์ฝ์์ ์๋ก ๋ค์ด์ค๋ ์ํ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ OnConsolerStatusListener๋ฅผ ์ ๊ณตํฉ๋๋ค.
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusManager statusManager = lc.getStatusManager();
OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();
statusManager.add(onConsoleListener);
StatusListener๋ ๋ฑ๋ก๋ ํ ์๋ก ๋ค์ด์ค๋ ์ํ ์ด๋ฒคํธ์ ๋ํ ๋ฉ์์ง๋ฅผ ์์ ํฉ๋๋ค. ํ์ง๋ง ๋ฆฌ์ค๋ ๋ฑ๋ก ์ด์ ์ ๋ฐ์ก๋ ๋ฉ์์ง๋ค์ ์์ ํ์ง ์๊ธฐ์, Configuration ๊ณผ์ ์ค StatusListener์ ๋ฑ๋ก์ ๊ฐ์ฅ ์์ ๋๋ ๊ฒ์ด ์ข์ ๋ฑ๋ก ๋ฐฉ๋ฒ์ ๋๋ค.
Configuration ํ์ผ์ ํ๋ ํน์ ์ด์์ StatusListener๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. logback.xml์ StatusListener๋ฅผ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
... the rest of the configuration file
</configuration>
StatusListener๋ ์์คํ ๋ณ์๋ก์จ ์ ๋ฌํ ์๋ ์์ต๋๋ค. ๋ณ์์ "logback.statusListenerClass"์ผ๋ก ์ง์ ํฉ๋๋ค. ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณต๋๋ StatusListener์ ์ข ๋ฅ๋ OnConsoleStatusListener, OnErrorConsoleStatusListener, NopStatusListener๊ฐ ์กด์ฌํฉ๋๋ค.
java -Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener ...
ch.qos.logback.core.status
OnConsoleStatusListener
์ฝ์์ ์ถ๋ ฅ
System.out
OnErrorConsoleStatusListener
System.err๋ฅผ ํตํด ์ถ๋ ฅ
System.err
NopStatusListener
์ํ ๋ฉ์์ง drop (๋ฌด์)
StatusListener๊ฐ ์ง์ ๋์ง ์์ผ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ์ํ ๋ฉ์์ง๋ ์ถ๋ ฅํ์ง ์์ต๋๋ค. ์ด๋ NopStatusListener๋ฅผ ๋ฆฌ์ค๋๋ก ์ง์ ํ์ ๋์ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค.
logback-classic ์ค์ง์ํค๊ธฐ
logback-classic ๋ชจ๋์ ์ํด ์ฌ์ฉ๋๋ ๋ฆฌ์์ค๋ฅผ ํด์ ์ํฌ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ logback context๋ฅผ ์ค์ง์ํค๋ ๊ฒ์ ๋๋ค. context๋ฅผ ์ค์ง์ํค๋ฉด context๋ฅผ ํตํด์ logger์ ๋ถ์ฐฉ๋์๋ ๋ชจ๋ appender๋ค์ด close ๋๋ฉฐ, active ์ํ์ ์ค๋ ๋๋ฅผ ์ฐจ๋ก๋๋ก ์ค์ง์ํต๋๋ค.
import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
...
// assume SLF4J is bound to logback-classic in the current environment
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();
์์ ์ฝ๋๋ LoggerContext๋ฅผ ์ค์ง์ํค๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. loggerContext.stop() ๋ฉ์๋๋ ServletContextListener์ contextDestroyed ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๋ก ์ธํด logback-classic์ด ์ ์ง๋๋ฉฐ ์ฌ์ฉํ๋ ๋ฆฌ์์ค๋ค์ ํด์ ํฉ๋๋ค.
๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก JVM shutdown hook์ ์ด์ฉํด์ logback-classic์ ์ค์ง์ํฌ ์ ์์ต๋๋ค. ์ฐ์ configuration ํ์ผ์ shutdownHook ๋๋ ํฐ๋ธ๋ฅผ ์ถ๊ฐํด์ค๋๋ค. shutdownHook ๋๋ ํฐ๋ธ์ class ์์ฑ์ผ๋ก ์ง์ ํ shutdown hook ํด๋์ค๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ๋ง์ฝ ์๋ฌด ์์ฑ์ ์ง์ ํ์ง ์๋๋ค๋ฉด ๊ธฐ๋ณธ์ผ๋ก DefaultShutdownHook ํด๋์ค๋ก ์ค์ ๋ฉ๋๋ค.
<configuration debug="true">
<!-- in the absence of the class attribute, assume
ch.qos.logback.core.hook.DefaultShutdownHook -->
<shutdownHook/>
....
</configuration>
DefaultShutdownHook์ hook ๋ฐ์ ํ ๊ณง๋ฐ๋ก(delay 0 by default) logback context๋ฅผ ์ค์ง์ํต๋๋ค. context ์ค์ง์๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ก๊ทธ ํ์ผ ์์ถ ์์ ์ด ์ผ์ด๋๋ ๊ฒ์ ๋๋นํด ์ต๋ 30์ด์ delay๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. JVM ์ข ๋ฃ ํ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ๋์ํ๋ ์์ถ ์์ ๋ฑ์ ์๋ฃํ ์ ์๋๋ก ํ๊ธฐ ์ํด์ ๋จ์ํ <shutdownHook/> ๋๋ ํฐ๋ธ๋ง์ ์ง์ ํ๋ฉด ๋ฉ๋๋ค. ์น์๋ฒ์์๋ webShutdownHook์ด ์๋์ผ๋ก shutdownHook ๋๋ ํฐ๋ธ๋ฅผ ์ง์ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ์ค์ ์ ํ์ง ์๋๋ก ํฉ๋๋ค (์ค์ ์ค๋ณต ๋ฐ์ ๊ฐ๋ฅ).
servlet-api 3.x ์ดํ์๋ logback-classic์ด ์๋์ผ๋ก ์น ์๋ฒ์๊ฒ ServletContanierInitialzer๋ฅผ implements ํ๋ LogbackServletContatinerInitializer๋ฅผ ์ค์นํฉ๋๋ค. LogbackServletContatinerInitializer๋ LogbackServletContextListener๋ฅผ ์๋์ผ๋ก ๋ฑ๋กํ๋๋ฐ ์ด ๋ฆฌ์ค๋๋ฅผ ํตํด ์น ์๋ฒ๊ฐ stop ํน์ reload ๋ ๋ ์๋์ผ๋ก logback-classic context๋ฅผ ์ค์ง์์ผ์ค๋๋ค.
๋ง์ฝ ์๋์ผ๋ก ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๋ ๊ฒ์ ์์น ์๋๋ค๋ฉด web.xml ํ์ผ์ logbackDisableServletContainerInitializer๋ฅผ ์ธํ ํจ์ผ๋ก์จ ์๋ ๋ฑ๋ก์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
<web-app>
<context-param>
<param-name>logbackDisableServletContainerInitializer</param-name>
<param-value>true</param-value>
</context-param>
....
</web-app>
Last updated