[목표]
- Spring 의 로깅을 남길 수 있다.
- 웹 성능을 테스트 할 수 있다.
스프링 프레임워크에서는 LogBack을 활용해서 로그를 남길 수 있다.
Spring boot 는 Commons Logging(org.apache.commons.logging) 를 사용하는데, 기본 설정자로서, Log4J2, Java Util Logging, 그리고 오늘 우리가 알아볼 LogBack
을 사용합니다.
Logging 의 Level 은 총 크게 4단계로 나눠집니다.
- ERROR - 예상하지 못한 심각한 문제가 발생하여 즉시 조사해야 함.
- WARN - 로직상 유효성 확인, 예상 가능한 문제로 인한 예외처리 등을 남김, 서비스는 운영될 수 있지만, 주의해야 함.
- INFO - 운영에 참고할만한 사항으로, 중요한 비즈니스 프로세스가 완료됨
- DEBUG / TRACE - 개발 단계에서만 사용하고 운영 단계에서는 사용하지 않음
기본적으로는 ERROR
, WARN
, INFO
가 로깅이 되고, DEBUG
mode 를 추가할 경우 DEBUG
레벨의 로그가 추가되어집니다.
java -jar myapp.jar --debug
또는 debug=true
를 application.properties
에 추가합니다.
Console Output
그 외에도 File Output
이 있습니다. File Output
은 application.properties 에 logging.file
또는logging.path
를 해야 합니다.
만약 위의 규칙이 아니라, Custom Log
를 만들고 싶다면 어떻게 할까요?
이번 미션 과제의 과제이기도 한, Custom Log
각 Logging System 마다 아래 표와 같은 파일을 만들어 Custom 된 Logging 파일 임을 암시합니다.
Logging System | Cusomization |
---|---|
Logback | logback-spring.xml logback-spring.groovy , logback.xml or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK(Java Util Logging) | logging.properties |
여기서 LogBack
은 다음과 같이 사용할 수 있습니다.
- logback 환경을 설정한 뒤에, 아래와 같은 코드로 logging을 합니다.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.util.StatusPrinter; public class HelloWorld2 { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld2"); logger.debug("Hello world."); // print internal state LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); } }
- 만약 아무것도 설정하지 않고 위와 같은 코드를 작성한다면
BasicConfigurator
가 사용될 것입니다.
application.properties
가 아니라 logback-test.xml
와 같이 logback-xxx.xml
파일을 사용해 로그를 설정하는 경우, appender
,logger
,root
이 세 가지를 기억해야 한다.(XML 안에는 카멜케이스 컨벤션을 따라야 한다.)
어떻게 사용해야 하는지는 다음 코드를 살펴봅시다.
// sample.xml
<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>
<logger name="chapters.configuration" level="INFO"/>
<!-- Strictly speaking, the level attribute is not necessary since -->
<!-- the level of the root level is set to DEBUG by default. -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
logger 에는 어떤 클래스에 어떤 레벨의 로그를 남기겠다 라고 남기면,
17:34:07.578 [main] INFO chapters.configuration.MyApp3 - Entering application.
17:34:07.578 [main] INFO chapters.configuration.MyApp3 - Exiting application.
처럼 보입니다.
Appenders 는 크게 2가지 속성을 꼭 넣어야 하는데, name 과 Class입니다.
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--로깅이 기록될 위치-->
<file>${home}file.log</file>
<!--로깅 파일이 특정 조건을 넘어가면 다른 파일로 만들어 준다.-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${home}file-%d{yyyyMMdd}-%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>15MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 해당 로깅의 패턴을 설정 -->
<encoder>
<charset>utf8</charset>
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger - %m%n
</Pattern>
</encoder>
</appender>
이제 간단히 개념을 살펴봤다는 가정하에 작업하면서 알았던 부분에 대해서 써내려가볼까 합니다.
Spring 에 Log 를 남기는 방법은 크게 2가지가 있습니다.
application.properties
를 사용하는 것과, logback-xxx.xml
을 사용하는 것이다. 이번 미션에서 두개 다 사용해보면서, 최종적으로는 Spring Boot 가 자동으로 설정된 기능을 거의다 가져와서 사용하는 방식을 사용했다. applciation.properties
를 사용하는 방식을 사용했는데, 그 이유는 File 을 Logger 로 사용할 경우에 이슈가 있었기 때문입니다.
xml 내에서 Profile 별로 Log Configuration 을 변경할 수 있는 기능이 있습니다.
이 기능을 사용하면서, Logging을 테스트 하는데, File Logging을 사용하지 않는 Local Profile 에서도 계속해서 불필요하게 빈 파일의 Log File 을 만드는 것을 볼 수 있었습니다.
아래 File 형태로 Logger 할 경우의 XML 입니다.
<configuration debug="false">
<!--spring boot의 기본 logback base.xml은 그대로 가져간다.-->
<include resource="org/springframework/boot/logging/logback/base.xml" />
<include resource="file-appender.xml" />
<!-- logger name이 file일때 적용할 appender를 등록한다.-->
<logger name="file" level="INFO" >
<appender-ref ref="file" />
</logger>
</configuration>
<property name="home" value="log/" />
<!-- appender이름이 file인 consoleAppender를 선언 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--로깅이 기록될 위치-->
<file>${home}file.log</file>
<!--로깅 파일이 특정 조건을 넘어가면 다른 파일로 만들어 준다.-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${home}file-%d{yyyyMMdd}-%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>15MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 해당 로깅의 패턴을 설정 -->
<encoder>
<charset>utf8</charset>
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger - %m%n
</Pattern>
</encoder>
</appender>
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<include resource="org/springframework/boot/logging/logback/base.xml" />
<include resource="file-appender.xml" />
<springProfile name="local, test">
<root level="DEBUG">
<appender-ref ref="file-appender"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="file-appender"/>
</root>
</springProfile>
</configuration>
이렇게 하고 Profile을 local 로 하더라도 무조건 빈 파일의 로그가 만들어집니다.
이런 단점 때문에 나는 application.properties
에 설정하는 방법을 선택합니다.
이런 식으로, 각각의 프로필 마다 properties
을 만들어 prod 에서만 File Logging 이 될 수 있도록 설정합니다. 설정하지 않으면 Console 로 logging 됩니다.
//application-prod.properties
...
logging.file.name=/home/ubuntu/log/subway.log
logging.logback.rollingpolicy.max-file-size=15MB
logging.logback.rollingpolicy.max-history=30
[읽어볼만한 자료]
'가치관 쌓기 > 개발 돌아보기' 카테고리의 다른 글
Layered Architecture 의 단점이 무엇이라고 생각하는가? (7) | 2021.07.26 |
---|---|
직접 코딩으로 느껴본 Spring Data JPA와 Spring Data JDBC 의 차이점 (0) | 2021.07.18 |
[우아한테크코스Pro] 인수 테스트 기반 TDD - 2 [5/9] (0) | 2021.07.14 |
[우아한테크코스Pro] 인수 테스트 기반 TDD - 1 [5/9] (0) | 2021.07.01 |
[우아한테크코스Pro] 그럴듯한 서비스 만들기 - 2 [4/9] (0) | 2021.07.01 |
댓글