얼마전에 Spring의 기능을 참조할 일이 있어 Spring의 레퍼런스 프로젝트인 spring-petclinic 를 내려받게 되었다.프로젝트 구조를 살펴보는 중 생소한 파일이 발견되었다.
바로 ‘logback.xml’ 파일이었는데, 직감적으로 “아! 어느새 log4j를 대체하는 기술이 나온 모양이구나”하는 생각이 들었다. 한동안 기술 트랜드에서 너무 벗어나 있었다는 생각이 다시금 들면서 이놈이 뭔지 좀 살펴보기로 했다.
logback 홈페이지에 들어가 보면 logback을 이렇게 소개한다.
“log4j 프로젝트의 후계자로 만들어졌다”
log4j개발자가 거의 지난 10년동안 log4j가 사용되면서 불편(?)했던 내용들을 모두 개선해서 logback이라는 제품을 만들어 낸 듯한 느낌이다.
개발자가 소개하는 log4j 에서 logback으로 옮겨야 하는 여러 이유들 중 특히 내가 관심이 가는 몇가지 항목들은 다음과 같다.
- Automatic Reloading Configuration file
- 필자에게는 logback을 도입해야 하는 제일 중요한 이유라고 생가되는 기능이다.
- log4j를 사용하던 시절(?)에는 로깅 레벨을 WARN -> INFO 등으로 변경하게 되면 Application(WAS)를 다시 시작했어야 했지만 logback 에서는 그럴 필요가 없다. 설정 파일을 변경하면 지정된 시간이 지나게 되면 파일의 변경을 감지하고 다시 읽어들인다.
- Graceful Recovery from I/O Failures
- 기존 log4j에서 FileAppender 를 사용하여 로그를 파일서버에 저장하는 경우, 파일서버에 문제가 있어 I/O fail이 나면 Application(was)를 재시작 했어야 했지만 logback에서는 파일 서버가 정상으로 돌아오면 에러 상황에서 빠르게 자동으로 복구가 된다.
- Automatic Compress
- 아마도 기존에 log4j를 사용해서 파일로 로그를 떨어뜨려 놓는 경우 별도의 배치 프로그램을 이용해서 로그파일을 압축하고 다른 곳으로 옮겨놓는 작업을 많이 해 보았을 것이라 생각된다. logback에서는 로그 파일의 자동 압축을 지원하고, 시간(파일의 갯수)이 지난 파일을 자동으로 삭제하는 기능도 제공을 한다.
- 로그 파일을 거대해서 압축하는데 시간이 오래 걸린다 해도 비동기 방식으로 동작하므로 application의 성능에는 영향을 주지 않는다.
- Prudnect Mode
- 다수의 JVM 인스턴스에서 같은 로그 파일을 사용하여 로그를 “안전하게” 기록할 수 있는 기능을 제공한다고 한다. 어떤 제한이 있는것 같다고 하는데 내부적으로 비동기 큐를 사용하고 있는 것이 아닌가 추측이 된다.
- 정확하게 확인해 보지는 않았지만 이런 모델들이 보통 문제를 많이 일으키는 관계로 꼭 필요하지 않다면 되도록 사용하지 않는 것이 좋을 것 같다는 생각이다.
- Conditional Processing Configurations
- 기존에는 개발환경과 운영환경에 별도의 설정파일을 적용-개발환경에서는 로깅레벨을 DEBUG, 운영환경에서는 WARN-시키기 위해 로깅 설정파일을 분리해 놓고 사용하던 경험들이 있을 것이라 생각된다.
- logback에서는 설정 파일에 if-then-else 의 조건문을 사용할 수 있어 설정 파일 하나로만 개발-운영 환경을 모두 커버할 수 있도록 만드는 것이 가능한다.
- Stack Traces with Packaging Data
프로젝트에 적용해 보기
1. 디펜던시 설정
logbook 응 사용하기 위해서는 logback-core, logback-classic, slf4j-api jar들이 필요한다. 디펜던시는 아래와 같이 설정한다.
메이븐을 사용하고 있다면 – [ pom.xml ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | < dependency > < groupId >ch.qos.logback</ groupId > < artifactId >logback-core</ artifactId > < version >1.1.2</ version > </ dependency > < dependency > < groupId >ch.qos.logback</ groupId > < artifactId >logback-classic</ artifactId > < version >1.1.2</ version > </ dependency > < dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-api</ artifactId > < version >1.7.10</ version > </ Dependency > <!— 조건부 설정을 사용하려면 아래의 디펜던시를 추가해 주어야 한다. —> < dependency > < groupId >org.codehaus.janino</ groupId > < artifactId >janino</ artifactId > < version >2.7.7</ version > </ dependency > |
그래들을 사용하고 있다면 – [build.gradle]
1 2 3 4 5 | compile 'ch.qos.logback:logback-classic:1.1.2'
compile 'ch.qos.logback:logback-core:1.1.2'
compile 'org.slf4j:slf4j-api:1.7.10' // 조건부 설정을 사용하려면 아래의 디팬던시를 추가해 주어야 한다 compile 'org.codehaus.janino:janino:2.7.7' |
2. logback.xml 파일의 설정은 아래와 같이 한다. 주석으로 처리한 부분을 잘 읽어보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <? xml version = "1.0" encoding = "UTF-8" ?> <!-- 30초마다 설정 파일의 변경을 확인한다. 파일이 변경되면 다시 로딩한다 --> < configuration scan = "true" scanPeriod = "30 seconds" > <!-- 외부 설정파일을 사용할 수 있다. --> < property resource = "resource.properties" /> < 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 > < appender name = "FILE" class = "ch.qos.logback.core.rolling.RollingFileAppender" > < file >${APP_HOME}/sujemall-webapp.log</ file > < rollingPolicy class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > <!-- 파일이 하루에 한개씩 생성된다 --> < fileNamePattern >sujemall-webapp.%d{yyyy-MM-dd}.log</ fileNamePattern > <!-- maxHIstory 설정은 위 부분에 롤링 정책에 따라 적용되 된다고 보면된다. 위 설정데로 라면 30일이 지난 파일은 삭제가 된다.--> < maxHistory >30</ maxHistory > </ rollingPolicy > < encoder > < pattern >%-4relative [%thread] %-5level %logger{35} - %msg%n</ pattern > </ encoder > </ appender > < logger name = "org.springframework" level = "info" /> < logger name = "org.hibernate" level = "debug" /> < logger name = "com.sujemall.webapp" level = "debug" /> < if condition = 'property("RUN_MODE").equals("SERVICE")' > < then > <!-- 설정파일에 RUN_MODE 가 SERVICE로 정의되어 있으면 로깅 레벨을 INFO로 지정 --> < root level = "info" > < appender-ref ref = "console" /> < appender-ref ref = "FILE" /> </ root > </ then > <!-- 설정파일에 RUN_MODE 가 SERVICE로 정의되어 있지 않으면 로깅 레벨을 DEBUG 지정 --> < else > < root level = "debug" > < appender-ref ref = "console" /> < appender-ref ref = "FILE" /> </ root > </ else > </ if > </ configuration > |
3. 로그 찍기는 slf4j api를 사용하는 기존의 방식과 크게 다르지 않다. 마커를 이용해서 로그를 찍어봤다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package com.sujemall.webapp.service; import com.sujemall.webapp.model.User; import com.sujemall.webapp.repository.UserRepository; import com.sujemall.webapp.utils.CommonUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Created by yhlee on 15. 1. 12.. */ @Service public class UserServiceImpl implements UserService { static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl. class ); @Autowired private UserRepository userRepository; @Override @Transactional public User enrollUser(User user) { user.setPassword(CommonUtils.hashString(user.getPassword())); user = userRepository.save(user); LOGGER.info( "#### Success Save User : UserName is {}, Email is {} " ,user.getUserName(), user.getMainEmail()); return user; } } |
위와같이 설정하고 application을 돌려보면 아래와 같이 로그가 잘 찍히는 것을 확인할 수 있다.
출처 : http://knot.tistory.com/92
'JAVA > Spring' 카테고리의 다른 글
Spring boot yml 파일 사용 (1) | 2019.03.21 |
---|---|
Mapper XML 파일 (0) | 2016.06.23 |
iBatis MyBatis 차이 (0) | 2016.06.17 |
RequestMapping 핸들러 매핑 정의 (0) | 2016.06.08 |
Spring xml 태그 설명 (0) | 2016.06.07 |