๐ฟ Spring Boot Logging: Logback ์ค์ ์ต์ ํ ๋์์ ! ๐

์๋ ํ์ธ์, ๊ฐ๋ฐ์ ์ฌ๋ฌ๋ถ! ์ค๋์ Spring Boot์ ๋ก๊น ์์คํ , ํนํ Logback ์ค์ ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊น์ด ์๊ฒ ํํค์ณ๋ณผ ๊ฑฐ์์. ๋ก๊น ์ด ๋ญ ๋ณ๊ฑฐ๋๊ณ ์? ใ ใ ใ ์ด๋ฆผ๋ ์์ฃ ! ๋ก๊น ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๊ณผ ๊ท๋ผ๊ณ ํ ์ ์์ด์. ์ ๋๋ก ์ค์ ํ๋ฉด ๊ฐ๋ฐ ์์ฐ์ฑ๊ณผ ์ด์ ํจ์จ์ฑ์ด ์ฅ์ฅ ์ฌ๋ผ๊ฐ๋ค๊ณ ์! ๐
์, ์ด์ ๋ถํฐ Spring Boot์ Logback์ ์ธ๊ณ๋ก ๋น ์ ธ๋ณผ๊น์? ์ค๋น๋์ จ๋์? ๊ทธ๋ผ ๊ณ ๊ณ ์ฝ~! ๐โโ๏ธ๐จ
๐ Spring Boot์ Logback์ ๋ง๋จ: ๋ก๊น ์ ์๋ก์ด ์งํ
Spring Boot๋ ๊ธฐ๋ณธ์ ์ผ๋ก Logback์ ๋ก๊น ํ๋ ์์ํฌ๋ก ์ฌ์ฉํด์. ์ ํํ Logback์ผ๊น์? ๊ทธ๊ฑด ๋ฐ๋ก Logback์ด ์ฑ๋ฅ๊ณผ ์ ์ฐ์ฑ ๋ฉด์์ ๋ค๋ฅธ ๋ก๊น ํ๋ ์์ํฌ๋ค์ ์๋ํ๊ธฐ ๋๋ฌธ์ด์์! ๐
Logback์ Log4j์ ํ์์์ผ๋ก, ๋ ๋น ๋ฅด๊ณ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ด๋ฉฐ, ์๋ ๋ฆฌ๋ก๋ ๊ฐ์ ์ฟจํ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํด์. Spring Boot์ ํจ๊ป๋ผ๋ฉด ๊ฑฐ์ ์๋ฒฝํ ์กฐํฉ์ด๋ผ๊ณ ํ ์ ์์ฃ ! ๐
๐ Logback์ ์ฃผ์ ํน์ง:
- ๋น ๋ฅธ ์คํ ์๋์ ๋ฎ์ ๋ฉ๋ชจ๋ฆฌ ์ ์ ์จ
- XML, Groovy ๊ธฐ๋ฐ์ ์ค์ ๊ฐ๋ฅ
- ๋ก๊ทธ ํ์ผ ์๋ ์์ถ ๋ฐ ๋กค์ค๋ฒ
- ์กฐ๊ฑด๋ถ ์ฒ๋ฆฌ๋ฅผ ํตํ ์ ์ฐํ ์ค์
- ํํฐ๋ฅผ ์ด์ฉํ ์ธ๋ฐํ ๋ก๊ทธ ์ ์ด
์ด๋ฐ ํน์ง๋ค ๋๋ถ์ Logback์ ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ ๋ถํฐ ์๊ท๋ชจ ํ๋ก์ ํธ๊น์ง ๋๋ฃจ๋๋ฃจ ์ฌ์ฉ๋๊ณ ์์ด์. ์ฌ์ง์ด ์ฌ๋ฅ๋ท ๊ฐ์ ์ฌ๋ฅ ๊ณต์ ํ๋ซํผ์์๋ Logback์ ํ์ฉํด ์์คํ ๋ชจ๋ํฐ๋ง๊ณผ ๋๋ฒ๊น ์ ํจ์จ์ ์ผ๋ก ํ๊ณ ์๋ค๊ณ ํด์! ๐
์, ์ด์ Logback์ด ์ผ๋ง๋ ๋๋จํ์ง ์๊ฒ ์ฃ ? ๊ทธ๋ผ ์ด์ ๋ถํฐ ๋ณธ๊ฒฉ์ ์ผ๋ก Logback ์ค์ ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณผ๊ฒ์. ์ค๋น๋์ จ๋์? Let's dive in! ๐โโ๏ธ
๐ Logback ์ค์ ์ ๊ธฐ๋ณธ: logback-spring.xml
Logback ์ค์ ์ ํต์ฌ์ ๋ฐ๋ก logback-spring.xml
ํ์ผ์ด์์. ์ด ํ์ผ๋ง ์ ๋๋ก ์์ฑํ๋ฉด ์ฌ๋ฌ๋ถ์ ๋ก๊น
์์คํ
์ ๊ทธ์ผ๋ง๋ก ๋ ๊ฐ๋ฅผ ๋จ ๋ฏ์ด ๋ ์์ค๋ฅผ ๊ฑฐ์์! โ๏ธ
๋จผ์ , ๊ธฐ๋ณธ์ ์ธ logback-spring.xml
ํ์ผ์ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ณผ๊น์?
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
์ด๊ฒ ๋ฐ๋ก ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ Logback ์ค์ ์ด์์. ํ๋์ฉ ๋ฏ์ด๋ณผ๊น์? ๐
<configuration>
: Logback ์ค์ ์ ๋ฃจํธ ์๋ฆฌ๋จผํธ์์.<appender>
: ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ด๋์ ์ถ๋ ฅํ ์ง ์ ์ํด์. ์ฌ๊ธฐ์๋ ์ฝ์์ ์ถ๋ ฅํ๋๋ก ์ค์ ํ์ด์.<encoder>
: ๋ก๊ทธ ๋ฉ์์ง์ ํ์์ ์ ์ํด์.<pattern>
: ์ค์ ๋ก๊ทธ ๋ฉ์์ง์ ํจํด์ ์ ์ํด์. ์๊ฐ, ์ค๋ ๋, ๋ก๊ทธ ๋ ๋ฒจ, ๋ก๊ฑฐ ์ด๋ฆ, ๋ฉ์์ง ์์๋ก ์ถ๋ ฅ๋๋๋ก ํ์ด์.<root>
: ๋ฃจํธ ๋ก๊ฑฐ์ ์ค์ ์ด์์. ๋ชจ๋ ๋ก๊ฑฐ์ ๋ถ๋ชจ๊ฐ ๋๋ ๋ก๊ฑฐ์ฃ .
์ด ๊ธฐ๋ณธ ์ค์ ๋ง์ผ๋ก๋ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ ์ ์์ง๋ง, ์ฐ๋ฆฌ๋ ์ฌ๊ธฐ์ ๋ฉ์ถ์ง ์์ ๊ฑฐ์์! ๋ ๋์, ๋ ํจ์จ์ ์ธ ๋ก๊น ์์คํ ์ ๋ง๋ค์ด๋ณผ ๊ฑฐ๋๊น์! ๐ช
๐ก Pro Tip: logback-spring.xml
ํ์ผ์ src/main/resources
๋๋ ํ ๋ฆฌ์ ์์น์ํค์ธ์. Spring Boot๊ฐ ์๋์ผ๋ก ์ด ํ์ผ์ ์ฐพ์ ์ค์ ์ ์ ์ฉํ ๊ฑฐ์์!
์, ์ด์ ๊ธฐ๋ณธ์ ์ธ ์ค์ ํ์ผ์ ๊ตฌ์กฐ๋ฅผ ์์์ผ๋, ๋ณธ๊ฒฉ์ ์ผ๋ก ์ด ํ์ผ์ ํ๋ํด๋ณผ๊น์? ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ๊ฐ๋ฅผ ๋ฌ์์ค ์๊ฐ์ด์์! ๐
๐จ Logback ์ค์ ์ต์ ํ: ๋ก๊ทธ ๋ ๋ฒจ ์กฐ์ ์ ๋ง๋ฒ
๋ก๊ทธ ๋ ๋ฒจ์ ๋ก๊น ์์คํ ์ ์ฌ์ฅ์ด๋ผ๊ณ ํ ์ ์์ด์. ์ ์ ํ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ ์ ํ์ํ ์ ๋ณด๋ง์ ํจ๊ณผ์ ์ผ๋ก ์์งํ๊ณ , ๋ถํ์ํ ๋ก๊ทธ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ฅผ ๋ฐฉ์งํ ์ ์์ฃ . ๊ทธ๋ผ ์ด๋ป๊ฒ ๋ก๊ทธ ๋ ๋ฒจ์ ์ต์ ํํ ์ ์์๊น์? ๐ค
Logback์์ ์ ๊ณตํ๋ ๋ก๊ทธ ๋ ๋ฒจ์ ๋ค์๊ณผ ๊ฐ์์ (๋ฎ์ ์์๋ถํฐ):
- TRACE
- DEBUG
- INFO
- WARN
- ERROR
๊ฐ ๋ ๋ฒจ์ ํน์ง์ ์ดํด๋ณผ๊น์?
๐ญ ๋ก๊ทธ ๋ ๋ฒจ์ ํน์ง:
- TRACE: ๊ฐ์ฅ ์์ธํ ๋ก๊ทธ ๋ ๋ฒจ. ๊ฐ๋ฐ ์ค ๋งค์ฐ ์์ธํ ์ ๋ณด๊ฐ ํ์ํ ๋ ์ฌ์ฉํด์.
- DEBUG: ๊ฐ๋ฐ ์ ๋๋ฒ๊น ๋ชฉ์ ์ผ๋ก ์ฌ์ฉํด์. ์ด์ ํ๊ฒฝ์์๋ ๋ณดํต ๋นํ์ฑํํฉ๋๋ค.
- INFO: ์ผ๋ฐ์ ์ธ ์๋ ์ ๋ณด๋ฅผ ๋ํ๋ด์. ์ด์ ํ๊ฒฝ์ ๊ธฐ๋ณธ ๋ก๊ทธ ๋ ๋ฒจ๋ก ๋ง์ด ์ฌ์ฉ๋ผ์.
- WARN: ์ ์ฌ์ ์ธ ๋ฌธ์ ๋ฅผ ๋ํ๋ด์ง๋ง, ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ณ์ ์คํ๋ ์ ์๋ ์ํฉ์ด์์.
- ERROR: ์ฌ๊ฐํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ ๋ํ๋ด์. ์ฆ์ ์กฐ์น๊ฐ ํ์ํ ์ํฉ์ด์ฃ .
์, ์ด์ ์ด ๋ก๊ทธ ๋ ๋ฒจ์ ์ด๋ป๊ฒ ์ค์ ํ๋ฉด ์ข์๊น์? ์ฌ๊ธฐ ๋ช ๊ฐ์ง ํ์ ๋๋ฆด๊ฒ์! ๐
- ํจํค์ง๋ณ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ : ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ ํจํค์ง๋ง๋ค ๋ค๋ฅธ ๋ก๊ทธ ๋ ๋ฒจ์ ์ค์ ํ ์ ์์ด์. ์๋ฅผ ๋ค์ด, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ จ ํจํค์ง๋ ์ข ๋ ์์ธํ ๋ก๊ทธ๊ฐ ํ์ํ ์ ์์ฃ .
- ํ๊ฒฝ๋ณ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ : ๊ฐ๋ฐ ํ๊ฒฝ๊ณผ ์ด์ ํ๊ฒฝ์ ๋ก๊ทธ ๋ ๋ฒจ์ ๋ค๋ฅด๊ฒ ๊ฐ์ ธ๊ฐ๋ ๊ฒ์ด ์ข์์. ๊ฐ๋ฐ ํ๊ฒฝ์์๋ DEBUG ๋ ๋ฒจ๋ก, ์ด์ ํ๊ฒฝ์์๋ INFO ๋ ๋ฒจ๋ก ์ค์ ํ๋ ์์ด์ฃ .
- ๋์ ๋ก๊ทธ ๋ ๋ฒจ ๋ณ๊ฒฝ: ์ด์ ์ค์๋ ๋ก๊ทธ ๋ ๋ฒจ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋๋ก ์ค์ ํ๋ฉด ๋งค์ฐ ์ ์ฉํด์. ๋ฌธ์ ์ํฉ์ด ๋ฐ์ํ์ ๋ ๋ก๊ทธ ๋ ๋ฒจ์ ์ผ์์ ์ผ๋ก ๋ฎ์ถฐ์ ๋ ์์ธํ ์ ๋ณด๋ฅผ ์ป์ ์ ์๊ฑฐ๋ ์.
์ด๋ฐ ์ค์ ์ logback-spring.xml
์ ์ด๋ป๊ฒ ๋ฐ์ํ ์ ์์๊น์? ๋ค์ ์์ ๋ฅผ ๋ด์ฃผ์ธ์:
<configuration>
<!-- ์ฝ์ ์ ํ๋ ์ค์ -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- ๋ฃจํธ ๋ก๊ฑฐ ์ค์ -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<!-- ํจํค์ง๋ณ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ -->
<logger name="com.example.myapp.controller" level="DEBUG"/>
<logger name="com.example.myapp.service" level="INFO"/>
<logger name="com.example.myapp.repository" level="WARN"/>
<!-- ์คํ๋ง ํ๋ ์์ํฌ ๊ด๋ จ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ -->
<logger name="org.springframework" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
</configuration>
์ด๋ ๊ฒ ์ค์ ํ๋ฉด ๊ฐ ํจํค์ง๋ง๋ค ๋ค๋ฅธ ๋ก๊ทธ ๋ ๋ฒจ์ ์ ์ฉํ ์ ์์ด์. ์ปจํธ๋กค๋ฌ๋ DEBUG ๋ ๋ฒจ๋ก ์์ธํ๊ฒ, ์๋น์ค ๊ณ์ธต์ INFO ๋ ๋ฒจ๋ก, ๋ฆฌํฌ์งํ ๋ฆฌ ๊ณ์ธต์ WARN ๋ ๋ฒจ๋ก ์ค์ ํ๋ค์. ์คํ๋ง๊ณผ ํ์ด๋ฒ๋ค์ดํธ ๊ด๋ จ ๋ก๊ทธ๋ ๋ฐ๋ก ์ค์ ํ๊ณ ์.
์ด๋ฐ ์์ผ๋ก ๋ก๊ทธ ๋ ๋ฒจ์ ์กฐ์ ํ๋ฉด, ํ์ํ ์ ๋ณด๋ ์ถฉ๋ถํ ์ป์ผ๋ฉด์๋ ๋ถํ์ํ ๋ก๊ทธ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ฅผ ๋ฐฉ์งํ ์ ์์ด์. ์์ ์ผ์์ด์กฐ ์๋๊ฒ ์ด์? ๐
๐ก Pro Tip: ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์ ์ด์ํ ๋๋, ์ฌ์ฉ์ ํ๋๊ณผ ๊ด๋ จ๋ ์ค์ํ ์ด๋ฒคํธ(์: ๊ฑฐ๋ ์ฑ์ฌ, ํ์ ๊ฐ์ ๋ฑ)๋ INFO ๋ ๋ฒจ๋ก, ์์คํ ๋ด๋ถ ๋์์ DEBUG ๋ ๋ฒจ๋ก ์ค์ ํ๋ ๊ฒ์ด ์ข์์. ์ด๋ ๊ฒ ํ๋ฉด ์ค์ํ ๋น์ฆ๋์ค ๋ก์ง์ ๋์น์ง ์์ผ๋ฉด์๋, ํ์ํ ๋ ์์ธํ ์์คํ ๋์๋ ํ์ธํ ์ ์๊ฑฐ๋ ์!
์, ์ด์ ๋ก๊ทธ ๋ ๋ฒจ ์ค์ ์ ๋ง๋ฒ์ ์ตํ์ผ๋, ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ ์ค๋น๊ฐ ๋์๋์? ๋ก๊ทธ ์ถ๋ ฅ ํ์์ ์์๊ฒ ๊พธ๋ฏธ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ ์ฐจ๋ก์์! ๐จโจ
๐ ๋ก๊ทธ ๋ฉ์์ง ์์๊ฒ ๊พธ๋ฏธ๊ธฐ: ํจํด ๋ ์ด์์์ ๋ง๋ฒ
๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์์๊ฒ ๊พธ๋ฏธ๋ ๊ฒ, ๋จ์ํ ๋ฏธ์ ์ธ ์ด์ ๋ง์ ์๋์์. ์ ๊ตฌ์ฑ๋ ๋ก๊ทธ ๋ฉ์์ง๋ ๊ฐ๋ ์ฑ์ ๋์ด๊ณ ๋ฌธ์ ํด๊ฒฐ ์๊ฐ์ ๋จ์ถ์์ผ์ค์. ๊ทธ๋ผ ์ด๋ป๊ฒ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ๊พธ๋ฐ ์ ์์๊น์? ๋ฐ๋ก ํจํด ๋ ์ด์์์ ์ฌ์ฉํ๋ ๊ฑฐ์์! ๐ญ
Logback์ ํจํด ๋ ์ด์์์ ์ ๋ง ๊ฐ๋ ฅํด์. ์๊ฐ, ๋ก๊ทธ ๋ ๋ฒจ, ์ค๋ ๋ ์ด๋ฆ, ๋ก๊ฑฐ ์ด๋ฆ, ๋ฉ์์ง ๋ฑ ๋ค์ํ ์ ๋ณด๋ฅผ ์ํ๋ ํ์์ผ๋ก ์กฐํฉํ ์ ์์ฃ . ๋ช ๊ฐ์ง ์ ์ฉํ ํจํด ์์๋ฅผ ์ดํด๋ณผ๊น์?
๐จ ์ ์ฉํ ํจํด ๋ ์ด์์ ์์:
%d{ํจํด}
: ๋ ์ง์ ์๊ฐ์ ํ์ํด์. ์:%d{yyyy-MM-dd HH:mm:ss.SSS}
%thread
: ํ์ฌ ์ค๋ ๋ ์ด๋ฆ์ ํ์ํด์.%-5level
: ๋ก๊ทธ ๋ ๋ฒจ์ 5์๋ฆฌ๋ก ๋ง์ถฐ ํ์ํด์. '-'๋ ์ผ์ชฝ ์ ๋ ฌ์ ์๋ฏธํด์.%logger{๊ธธ์ด}
: ๋ก๊ฑฐ ์ด๋ฆ์ ํ์ํด์. ๊ธธ์ด๋ฅผ ์ง์ ํ๋ฉด ๊ธด ์ด๋ฆ์ ์ถ์ฝํ ์ ์์ด์.%msg
: ์ค์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ํ์ํด์.%n
: ์ค๋ฐ๊ฟ์ ์๋ฏธํด์.%highlight(ํจํด){์์ ์คํ์ผ}
: ์ง์ ํ ํจํด์ ์์์ ์ ํ์.
์ด๋ฐ ์์๋ค์ ์กฐํฉํด์ ๋ฉ์ง ๋ก๊ทธ ํจํด์ ๋ง๋ค์ด๋ณผ๊น์? ์ฌ๊ธฐ ์์๊ฐ ์์ด์:
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
์ด ํจํด์ ์ฌ์ฉํ๋ฉด ๋ก๊ทธ๊ฐ ์ด๋ ๊ฒ ์ถ๋ ฅ๋ผ์:
2023-06-15 14:30:45.123 [main] INFO c.e.MyApp - ์ ํ๋ฆฌ์ผ์ด์
์ด ์์๋์์ต๋๋ค.
2023-06-15 14:30:46.234 [http-nio-8080-exec-1] DEBUG c.e.c.UserController - ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์๋: user123
2023-06-15 14:30:46.345 [http-nio-8080-exec-1] WARN c.e.s.UserService - ์๋ชป๋ ๋น๋ฐ๋ฒํธ ์
๋ ฅ: user123
์ด๋์? ํจ์ฌ ๋ณด๊ธฐ ์ข๊ณ ์ ๋ณด๋ ํ๋์ ๋ค์ด์ค์ฃ ? ๐
ํ์ง๋ง ์ฌ๊ธฐ์ ๋์ด ์๋์์! ๋ ๋ฉ์ง ๊ธฐ๋ฅ๋ค์ด ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ต๋๋ค. ์๋ฅผ ๋ค์ด, MDC(Mapped Diagnostic Context)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ก๊ทธ์ ์ถ๊ฐ์ ์ธ ์ปจํ ์คํธ ์ ๋ณด๋ฅผ ๋ฃ์ ์ ์์ด์. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ๊ธฐ๋ฅ์ด ํนํ ์ ์ฉํ ๊ฑฐ์์. ์ฌ์ฉ์ ID๋ ์ธ์ ID ๊ฐ์ ์ ๋ณด๋ฅผ ๋ชจ๋ ๋ก๊ทธ์ ์๋์ผ๋ก ํฌํจ์ํฌ ์ ์๊ฑฐ๋ ์!
MDC๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, ๋จผ์ ์ฝ๋์์ MDC์ ๊ฐ์ ๋ฃ์ด์ค์ผ ํด์:
import org.slf4j.MDC;
// ์ปจํธ๋กค๋ฌ๋ ์ธํฐ์
ํฐ์์
MDC.put("userId", user.getId());
MDC.put("sessionId", session.getId());
// ๋ก์ง ์คํ ํ
MDC.clear(); // ๊ผญ ํด๋ฆฌ์ด ํด์ฃผ์ธ์!
๊ทธ๋ฆฌ๊ณ ๋ก๊ทธ ํจํด์ MDC ๊ฐ์ ํฌํจ์ํค๋ฉด ๋ผ์:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %X{userId} %X{sessionId} - %msg%n</pattern>
์ด๋ ๊ฒ ํ๋ฉด ๋ก๊ทธ๊ฐ ์ด๋ฐ ์์ผ๋ก ์ถ๋ ฅ๋ผ์:
2023-06-15 14:35:12.345 [http-nio-8080-exec-2] INFO c.e.c.UserController - user123 ABC123XYZ - ์ฌ์ฉ์๊ฐ ํ๋กํ์ ์
๋ฐ์ดํธํ์ต๋๋ค.
์ด๋์? ์ด์ ๊ฐ ๋ก๊ทธ๊ฐ ์ด๋ค ์ฌ์ฉ์, ์ด๋ค ์ธ์ ์์ ๋ฐ์ํ๋์ง ํ๋์ ์ ์ ์์ฃ ? ์ด๋ฐ ์์ผ๋ก MDC๋ฅผ ํ์ฉํ๋ฉด ๋ก๊ทธ ๋ถ์์ด ํจ์ฌ ์ฌ์์ ธ์. ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ๋ค์ค ์ฌ์ฉ์ ํ๋ซํผ์์๋ ์ ๋ง ์ ์ฉํ ๊ฑฐ์์! ๐
๐ก Pro Tip: ๋ก๊ทธ ํจํด์ ์ค๊ณํ ๋๋ ํญ์ ๊ฐ๋ ์ฑ๊ณผ ์ฑ๋ฅ์ ๊ท ํ์ ๊ณ ๋ คํ์ธ์. ๋๋ฌด ๋ง์ ์ ๋ณด๋ฅผ ํฌํจ์ํค๋ฉด ๋ก๊ทธ ํ์ผ ํฌ๊ธฐ๊ฐ ๋น ๋ฅด๊ฒ ์ฆ๊ฐํ ์ ์์ด์. ๊ผญ ํ์ํ ์ ๋ณด๋ง ํฌํจ์ํค๊ณ , ๋ก๊ทธ ๋กํ ์ด์ ๊ณผ ์์ถ ์ ๋ต์ ์ ์ค์ ํ๋ ๊ฒ์ด ์ค์ํด์!
์, ์ด์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์์๊ณ ์ ์ฉํ๊ฒ ๊พธ๋ฏธ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ด์. ๋ค์์ ๋ก๊ทธ๋ฅผ ์ด๋์ ์ด๋ป๊ฒ ์ ์ฅํ ์ง ์์๋ณผ ์ฐจ๋ก์์. ํ์ผ ์ ํ๋์ ๋ก๊ทธ ๋กํ ์ด์ ์ ์ธ๊ณ๋ก ๋ค์ด๊ฐ๋ณผ๊น์? ๐ชโจ
๐ ๋ก๊ทธ ํ์ผ ๊ด๋ฆฌ์ ๋ฌ์ธ๋๊ธฐ: ํ์ผ ์ ํ๋์ ๋ก๊ทธ ๋กํ ์ด์
์ฝ์์ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ ๊ฒ๋ ์ข์ง๋ง, ์ค์ ์ด์ ํ๊ฒฝ์์๋ ๋ก๊ทธ๋ฅผ ํ์ผ๋ก ์ ์ฅํ๋ ๊ฒ์ด ํจ์ฌ ๋ ์ ์ฉํด์. ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ํ ๊ฐ์ง ๋ฌธ์ ๊ฐ ์๊ฒจ์. ๋ก๊ทธ ํ์ผ์ด ๋ฌดํ์ ์ปค์ง๋ฉด ์ด๋กํ์ฃ ? ๐ค ๋ฐ๋ก ์ด๋ ํ์ํ ๊ฒ ํ์ผ ์ ํ๋์ ๋ก๊ทธ ๋กํ ์ด์ ์ด์์!
ํ์ผ ์ ํ๋๋ ๋ง ๊ทธ๋๋ก ๋ก๊ทธ๋ฅผ ํ์ผ์ ์ถ๊ฐ(append)ํ๋ ์ญํ ์ ํด์. ๊ทธ๋ฆฌ๊ณ ๋ก๊ทธ ๋กํ ์ด์ ์ ๋ก๊ทธ ํ์ผ์ด ํน์ ์กฐ๊ฑด(ํฌ๊ธฐ๋ ์๊ฐ)์ ๋๋ฌํ์ ๋ ์๋ก์ด ํ์ผ์ ๋ง๋ค๊ณ ์ด์ ํ์ผ์ ๋ณด๊ดํ๋ ๊ธฐ๋ฅ์ด์์. ์ด ๋ ๊ฐ์ง๋ฅผ ์ ์กฐํฉํ๋ฉด ๋ก๊ทธ ๊ด๋ฆฌ๊ฐ ํ๊ฒฐ ์์ํด์ ธ์!
์, ๊ทธ๋ผ Logback์์ ์ด๋ป๊ฒ ํ์ผ ์ ํ๋์ ๋ก๊ทธ ๋กํ ์ด์ ์ ์ค์ ํ๋์ง ์ดํด๋ณผ๊น์? ๐ง
<configuration>
<property name="LOG_PATH" value="./logs" />
<property name="LOG_FILE_NAME" value="myapp" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
์ฐ์, ์ข ๋ณต์กํด ๋ณด์ด์ฃ ? ใ ใ ใ ํ๋์ฉ ๋ฏ์ด๋ณผ๊ฒ์! ๐
<property>
: ๋ก๊ทธ ํ์ผ ๊ฒฝ๋ก์ ์ด๋ฆ์ ๋ณ์๋ก ์ ์ํด์. ๋์ค์ ์ฌ์ฌ์ฉํ๊ธฐ ํธํ์ฃ !<appender>
: RollingFileAppender๋ฅผ ์ฌ์ฉํด์. ์ด๊ฒ ๋ฐ๋ก ๋ก๊ทธ ๋กํ ์ด์ ์ ํต์ฌ์ด์์!<file>
: ํ์ฌ ์์ฑ ์ค์ธ ๋ก๊ทธ ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํด์.<encoder>
: ๋ก๊ทธ ๋ฉ์์ง์ ํ์์ ์ ์ํด์. ์๊น ๋ฐฐ์ด ํจํด ๋ ์ด์์์ ์ฌ๊ธฐ์ ์ฌ์ฉํ๋ฉด ๋ผ์.<rollingPolicy>
: ๋ก๊ทธ ๋กํ ์ด์ ์ ์ฑ ์ ์ ์ํด์. ์ฌ๊ธฐ์๋ ์๊ฐ ๊ธฐ๋ฐ ์ ์ฑ ์ ์ฌ์ฉํ์ด์.<fileNamePattern>
: ๋กํ ์ด์ ๋ ๋ก๊ทธ ํ์ผ์ ์ด๋ฆ ํจํด์ ์ ์ํด์. ์ฌ๊ธฐ์๋ ๋ ์ง์ ์ธ๋ฑ์ค๋ฅผ ํฌํจํ๊ณ , gz๋ก ์์ถํ๋๋ก ํ์ด์.<timeBasedFileNamingAndTriggeringPolicy>
: ํ์ผ ํฌ๊ธฐ ๊ธฐ๋ฐ์ ํธ๋ฆฌ๊ฑฐ ์ ์ฑ ์ ์ถ๊ฐ๋ก ์ค์ ํ์ด์. 10MB๋ง๋ค ์ ํ์ผ์ ๋ง๋ค์ด์.<maxHistory>
: ์ต๋ 30์ผ์น์ ๋ก๊ทธ ํ์ผ๋ง ๋ณด๊ดํ๋๋ก ์ค์ ํ์ด์.
์ด๋ ๊ฒ ์ค์ ํ๋ฉด, ๋ก๊ทธ ํ์ผ์ด ํ๋ฃจ์ ํ ๋ฒ์ฉ, ๋๋ 10MB๊ฐ ๋ ๋๋ง๋ค ์๋ก์ด ํ์ผ๋ก ๋กค์ค๋ฒ๋๊ณ , 30์ผ์ด ์ง๋ ํ์ผ์ ์๋์ผ๋ก ์ญ์ ๋ผ์. ์์ ํธ๋ฆฌํ์ฃ ? ๐
๐ก Pro Tip: ์ฌ๋ฅ๋ท ๊ฐ์ ๋๊ท๋ชจ ํ๋ซํผ์์๋ ๋ก๊ทธ ์์ด ์์ฒญ๋๊ฒ ๋ง์ ๊ฑฐ์์. ์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋ก๊ทธ๋ฅผ ์ฌ๋ฌ ํ์ผ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข์์. ์๋ฅผ ๋ค์ด, ์๋ฌ ๋ก๊ทธ, ์ฌ์ฉ์ ํ๋ ๋ก๊ทธ, ์์คํ ๋ก๊ทธ ๋ฑ์ผ๋ก ๋๋ ์ ์์ฃ . ๊ฐ๊ฐ์ ๋ํด ๋ณ๋์ ์ ํ๋๋ฅผ ์ค์ ํ๋ฉด ๋ผ์!
์, ์ด์ ๋ก๊ทธ ํ์ผ ๊ด๋ฆฌ์ ๊ธฐ๋ณธ์ ๋ฐฐ์ ์ด์. ํ์ง๋ง ์ฌ๊ธฐ์ ๋์ด ์๋์์! ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ด ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋น๋๊ธฐ ๋ก๊น ์ ์ฌ์ฉํ๋ฉด ๋ก๊น ์ผ๋ก ์ธํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ ์ ํ๋ฅผ ์ต์ํํ ์ ์์ด์. ํ๋ฒ ์ดํด๋ณผ๊น์? ๐
<configuration>
<!-- ๊ธฐ์กด FILE ์ ํ๋ ์ค์ -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
<root level="INFO">
<appender-ref ref="ASYNC" />
</root>
</configuration>
์ด๋ ๊ฒ AsyncAppender๋ฅผ ์ฌ์ฉํ๋ฉด, ๋ก๊ทธ ๋ฉ์์ง๊ฐ ๋จผ์ ๋ฉ๋ชจ๋ฆฌ ํ์ ์ ์ฅ๋๊ณ , ๋ณ๋์ ์ค๋ ๋์์ ํ์ผ์ ๊ธฐ๋ก๋ผ์. ๋๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฃผ ์ค๋ ๋๋ ๋ก๊น ์์ ์ผ๋ก ์ธํด ๋ธ๋กํน๋์ง ์์์. ์ฑ๋ฅ ํฅ์์ ๋ง๋ฒ์ด์ฃ ! โจ
๊ทธ๋ฆฌ๊ณ ๋ ํ๋! ๋ก๊ทธ ํ์ผ์ ์์ถํ๋ ๊ฒ๋ ์์ง ๋ง์ธ์. ๋ก๊ทธ ํ์ผ์ ๋ณดํต ํ
์คํธ๋ผ ์์ถ๋ฅ ์ด ๋์์. gzip์ผ๋ก ์์ถํ๋ฉด ์ ์ฅ ๊ณต๊ฐ์ ํฌ๊ฒ ์ ์ฝํ ์ ์์ฃ . ์์ ์ค์ ์์ ์ด๋ฏธ .gz
ํ์ฅ์๋ฅผ ์ฌ์ฉํด ์๋ ์์ถ์ ์ ์ฉํ์ด์.
๐ Advanced Tip: ๋๊ท๋ชจ ์์คํ ์์๋ ๋ก๊ทธ๋ฅผ ์ค์ ์ง์ค์์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข์์. ELK ์คํ(Elasticsearch, Logstash, Kibana)์ด๋ Splunk ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ์๋ฒ์ ๋ก๊ทธ๋ฅผ ํ ๊ณณ์์ ๋ชจ์๋ณด๊ณ ๋ถ์ํ ์ ์์ด์. Logback์์๋ SocketAppender๋ฅผ ์ฌ์ฉํด ์ด๋ฐ ์์คํ ์ผ๋ก ๋ก๊ทธ๋ฅผ ์ ์กํ ์ ์๋ต๋๋ค!
์, ์ด์ ์ฌ๋ฌ๋ถ์ ๋ก๊ทธ ํ์ผ ๊ด๋ฆฌ์ ๋ฌ์ธ์ด ๋์์ด์! ๐ ํ์ผ ์ ํ๋์ ๋ก๊ทธ ๋กํ ์ด์ , ๋น๋๊ธฐ ๋ก๊น ๊น์ง ๋ง์คํฐํ์ผ๋ ์ด์ ์ด๋ค ์ํฉ์์๋ ๋ก๊ทธ ๊ด๋ฆฌ๋ฅผ ์๋ฒฝํ๊ฒ ํ ์ ์์ ๊ฑฐ์์. ์ฌ๋ฅ๋ท ๊ฐ์ ๋๊ท๋ชจ ํ๋ซํผ์์๋ ๋ฌธ์ ์์ด ๋ก๊ทธ๋ฅผ ๊ด๋ฆฌํ ์ ์๊ฒ ์ฃ ?
๋ค์ ์น์ ์์๋ ๋ก๊ทธ ํํฐ๋ง๊ณผ ๋ง์คํน์ ๋ํด ์์๋ณผ ๊ฑฐ์์. ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์ด๋ป๊ฒ ๋ณดํธํ๋ฉด์ ๋ก๊น ํ ์ ์์์ง, ํจ๊ป ์ดํด๋ณด์์! ์ค๋น๋์ จ๋์? Let's go! ๐
๐ต๏ธโโ๏ธ ๋น๋ฐ ์์์ ํ์ ์คํฌ: ๋ก๊ทธ ํํฐ๋ง๊ณผ ๋ง์คํน
์, ์ด์ ์ฐ๋ฆฌ๋ ๋ก๊ทธ๋ฅผ ์ด๋์ ์ด๋ป๊ฒ ์ ์ฅํ ์ง ์๊ฒ ๋์์ด์. ํ์ง๋ง ์ ๊น, ์ฌ๊ธฐ์ ์ค์ํ ๋ฌธ์ ๊ฐ ํ๋ ์์ด์. ๋ฐ๋ก ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์ด๋ป๊ฒ ๋ค๋ฃฐ ๊ฒ์ธ๊ฐ ํ๋ ๊ฑฐ์ฃ . ๐คซ
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์ฌ์ฉ์์ ๊ฐ์ธ์ ๋ณด, ๊ฒฐ์ ์ ๋ณด ๋ฑ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ฒ ๋ ๊ฑฐ์์. ์ด๋ฐ ์ ๋ณด๊ฐ ๊ทธ๋๋ก ๋ก๊ทธ์ ๋จ๋๋ค๋ฉด? ํฐ์ผ ๋๊ฒ ์ฃ ! ๐ฑ ๊ทธ๋์ ์ฐ๋ฆฌ์๊ฒ ๋ก๊ทธ ํํฐ๋ง๊ณผ ๋ง์คํน ๊ธฐ์ ์ด ํ์ํด์.
Logback์์๋ ํํฐ๋ฅผ ์ฌ์ฉํด ํน์ ๋ก๊ทธ๋ฅผ ์ ์ธํ๊ฑฐ๋, ์ปจ๋ฒํฐ๋ฅผ ์ฌ์ฉํด ํน์ ํจํด์ ๋ฐ์ดํฐ๋ฅผ ๋ง์คํนํ ์ ์์ด์. ์ด๋ป๊ฒ ํ๋์ง ์ดํด๋ณผ๊น์? ๐ง
1. ๋ก๊ทธ ํํฐ๋ง
๋จผ์ , ํน์ ํจํด์ ๋ก๊ทธ๋ฅผ ์์ ๊ธฐ๋กํ์ง ์๋๋ก ํํฐ๋งํด๋ณผ๊ฒ์. ์๋ฅผ ๋ค์ด, ๋น๋ฐ๋ฒํธ๊ฐ ํฌํจ๋ ๋ก๊ทธ๋ ๋ชจ๋ ์ ์ธํ๊ณ ์ถ๋ค๋ฉด ์ด๋ ๊ฒ ํ ์ ์์ด์:
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>return message.contains("password");</expression>
</evaluator>
<OnMatch>DENY</OnMatch>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
์ด ์ค์ ์ "password"๋ผ๋ ๋จ์ด๊ฐ ํฌํจ๋ ๋ชจ๋ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ๋ฌด์ํด์. ์์ ๋น๋ฐ ์์ ์คํ์ผ์ด์ฃ ? ๐
2. ๋ฐ์ดํฐ ๋ง์คํน
๋๋ก๋ ๋ก๊ทธ๋ฅผ ์์ ํ ์ ์ธํ๋ ๋์ , ๋ฏผ๊ฐํ ๋ถ๋ถ๋ง ๊ฐ๋ฆฌ๊ณ ์ถ์ ์ ์์ด์. ์ด๋ด ๋๋ ์ปจ๋ฒํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ผ์. ์๋ฅผ ๋ค์ด, ์ด๋ฉ์ผ ์ฃผ์์ ์ผ๋ถ๋ฅผ ๊ฐ๋ฆฌ๊ณ ์ถ๋ค๋ฉด:
<configuration>
<conversionRule conversionWord="maskedMsg"
converterClass="com.example.log.MaskingConverter" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %maskedMsg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
์ฌ๊ธฐ์ MaskingConverter
๋ ์ง์ ๊ตฌํํด์ผ ํ๋ ํด๋์ค์์. ์ด๋ ๊ฒ ๊ตฌํํ ์ ์์ฃ :
import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
public class MaskingConverter extends MessageConverter {
private static final String EMAIL_REGEX = "(\\w+)(\\.\\w+)*@(\\w+\\.)(\\w+)(\\.\\w+)*";
private static final String MASK = "$1****@$3$4";
@Override
public String convert(ILoggingEvent event) {
String message = event.getFormattedMessage();
return message.replaceAll(EMAIL_REGEX, MASK);
}
}
์ด ์ปจ๋ฒํฐ๋ ์ด๋ฉ์ผ ์ฃผ์์ ๋ก์ปฌ ํํธ(@ ์๋ถ๋ถ)๋ฅผ ๋ง์คํนํด์. ์๋ฅผ ๋ค์ด, "user.name@example.com"์ "user****@example.com"์ผ๋ก ๋ณํ๋์ฃ .
๐ก Pro Tip: ๋ง์คํน ๊ท์น์ ํ์ฌ์ ๋ณด์ ์ ์ฑ ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์ด์. ์ ์ฉ์นด๋ ๋ฒํธ, ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ ๋ฑ ๋ค์ํ ํํ์ ๋ฏผ๊ฐ ์ ๋ณด์ ๋ํด ๊ฐ๊ฐ ๋ค๋ฅธ ๋ง์คํน ๊ท์น์ ์ ์ฉํ ์ ์๋ต๋๋ค. ์ ๊ทํํ์์ ์ ํ์ฉํ๋ฉด ๊ฑฐ์ ๋ชจ๋ ํํ์ ๋ฐ์ดํฐ๋ฅผ ๋ง์คํนํ ์ ์์ด์!
์ด๋ ๊ฒ ํํฐ๋ง๊ณผ ๋ง์คํน์ ์ ์ฉํ๋ฉด, ๋ก๊ทธ์์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๋ณดํธํ ์ ์์ด์. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์ฌ์ฉ์์ ๊ฐ์ธ์ ๋ณด ๋ณดํธ๊ฐ ์ ๋ง ์ค์ํ๋๊น, ์ด๋ฐ ๊ธฐ์ ์ ํ์๊ฒ ์ฃ ?
ํ์ง๋ง ์ฃผ์ํ์ธ์! ๋ก๊ทธ ํํฐ๋ง๊ณผ ๋ง์คํน์ ๋๋ฌด ๊ณผ๋ํ๊ฒ ์ ์ฉํ๋ฉด ํ์ํ ์ ๋ณด๊น์ง ๋์น ์ ์์ด์. ํญ์ ๋ณด์๊ณผ ์ ์ฉ์ฑ ์ฌ์ด์ ๊ท ํ์ ์ ๋ง์ถ๋ ๊ฒ ์ค์ํด์. ๐
์, ์ด์ ์ฌ๋ฌ๋ถ์ ์ง์ ํ ๋ก๊ทธ ๋์๊ฐ ๋์์ด์! ๐ฅท ๋ก๊ทธ๋ฅผ ์์ฑํ๊ณ , ์ ์ฅํ๊ณ , ๊ด๋ฆฌํ๊ณ , ์ฌ์ง์ด ๋ฏผ๊ฐํ ์ ๋ณด๋ ๋ณดํธํ ์ ์๊ฒ ๋์์ผ๋๊น์. ์ด์ ๋ง์ง๋ง์ผ๋ก, ๋ชจ๋ ๊ฒ์ ์ข ํฉํด์ ์ค์ ์ด์ ํ๊ฒฝ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณผ๊น์? ์ค๋น๋์ จ๋์? ๋ง์ง๋ง ์คํผํธ ํ๋ฒ ํด๋ด์! ๐ช
๐ ์ค์ ์ ์ฉ: ์๋ฒฝํ Logback ์ค์ ์ ์ ์
๋๋์ด ๋ง์ง๋ง ๋จ๊ณ์ ๋๋ฌํ์ด์! ๐ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ชจ๋ ๊ฒ์ ์ข ํฉํด์, ์ค์ ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋ ์๋ฒฝํ Logback ์ค์ ์ ๋ง๋ค์ด๋ณผ ๊ฑฐ์์. ์ฌ๋ฅ๋ท ๊ฐ์ ๋๊ท๋ชจ ํ๋ซํผ์ ์ ์ฉํ ์ ์๋ ์์ค์ ์ค์ ์ด ๋ ๊ฑฐ์์. ์ค๋น๋์ จ๋์? ๐
๋จผ์ , ์ฐ๋ฆฌ์ ์ต์ข
logback-spring.xml
ํ์ผ์ ์ดํด๋ณผ๊ฒ์:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_PATH" value="./logs" />
<property name="LOG_FILE_NAME" value="myapp" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
<conversionRule conversionWord="maskedMsg"
converterClass="com.example.log.MaskingConverter" />
<logger name="com.example.myapp" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ASYNC" />
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ASYNC" />
</root>
</configuration>
์ฐ์, ์ ๋ง ์๋ฒฝํ ์ค์ ์ด์ฃ ? ๐ ์ด ์ค์ ์ด ์ด๋ค ์ผ์ ํ๋์ง ํ๋์ฉ ์ดํด๋ณผ๊ฒ์:
- ์ฝ์๊ณผ ํ์ผ ๋ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํด์.
- ํ์ผ ๋ก๊ทธ๋ ๋ ์ง๋ณ, ํฌ๊ธฐ๋ณ๋ก ๋กค๋ง๋๋ฉฐ, ์์ถ ์ ์ฅ๋ผ์.
- ๋น๋๊ธฐ ๋ก๊น ์ ์ฌ์ฉํด ์ฑ๋ฅ์ ์ต์ ํํ์ด์.
- ์ปค์คํ ๋ง์คํน ์ปจ๋ฒํฐ๋ฅผ ์ ์ฉํด ๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ๋ณดํธํด์.
- ์ ํ๋ฆฌ์ผ์ด์ ํจํค์ง๋ DEBUG ๋ ๋ฒจ๋ก, ๊ทธ ์ธ๋ INFO ๋ ๋ฒจ๋ก ๋ก๊น ํด์.
์ด ์ค์ ์ ์ฌ์ฉํ๋ฉด, ๊ฐ๋ฐ ์์๋ ์ฝ์์์ ์์ธํ ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์๊ณ , ์ด์ ํ๊ฒฝ์์๋ ํ์ผ๋ก ์์ ํ๊ฒ ๋ก๊ทธ๋ฅผ ์ ์ฅํ ์ ์์ด์. ๊ฒ๋ค๊ฐ ๋ฏผ๊ฐ ์ ๋ณด๋ ์๋์ผ๋ก ๋ง์คํน๋๋ ๋ณด์๋ ์๋ฒฝํ์ฃ !
๐ก Pro Tip: ์ค์ ์ด์ ํ๊ฒฝ์์๋ ๋ก๊ทธ ๋ ๋ฒจ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋๋ก ์ค์ ํ๋ ๊ฒ์ด ์ข์์. Spring Boot Actuator๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐํ์์ ๋ก๊ทธ ๋ ๋ฒจ์ ๋ณ๊ฒฝํ ์ ์๋ต๋๋ค. ๋ฌธ์ ์ํฉ์ด ๋ฐ์ํ์ ๋ ๋งค์ฐ ์ ์ฉํด์!
์, ์ด์ ์ ๋ง ์๋ฒฝํ Logback ์ค์ ์ด ์์ฑ๋์ด์. ์ด ์ค์ ์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฅ๋ท ๊ฐ์ ๋๊ท๋ชจ ํ๋ซํผ์์๋ ๋ก๊ทธ ๊ด๋ฆฌ๋ฅผ ์๋ฒฝํ๊ฒ ํ ์ ์์ ๊ฑฐ์์. ๋ก๊ทธ ์์ฑ๋ถํฐ ์ ์ฅ, ๊ด๋ฆฌ, ๋ณด์๊น์ง ๋ชจ๋ ๊ฒ์ ์ปค๋ฒํ์ผ๋๊น์! ๐
๋ง์ง๋ง์ผ๋ก, ๋ก๊น ์ ๋จ์ํ ๊ธฐ์ ์ ์ธ ๋ฌธ์ ๊ฐ ์๋๋ผ๋ ์ ์ ๊ธฐ์ตํ์ธ์. ์ข์ ๋ก๊น ์ ๋ต์ ๊ฐ๋ฐ ์์ฐ์ฑ์ ๋์ด๊ณ , ๋ฌธ์ ํด๊ฒฐ ์๊ฐ์ ๋จ์ถ์ํค๋ฉฐ, ์์คํ ์ ์์ ์ฑ์ ๋์ฌ์ค์. ์ฌ๋ฌ๋ถ์ ๋ก๊น ์ ๋ต์ด ์ด ๋ชจ๋ ๊ฒ์ ๋ฌ์ฑํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๊ฒ์! ๐
์ฌ๊ธฐ๊น์ง ๊ธด ์ฌ์ ์ ํจ๊ป ํด์ฃผ์ ์ ์ ๋ง ๊ฐ์ฌํด์. ์ด์ ์ฌ๋ฌ๋ถ์ Logback ๋ง์คํฐ๊ฐ ๋์์ด์! ๐ ์์ผ๋ก ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์์ ๋ก๊น ๋ฌธ์ ๋ก ๊ณ ๋ฏผํ๋ ์ผ์ ์์ ๊ฑฐ์์. ํ์ดํ ! ๐ช๐
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ