'스프링부트'에 해당되는 글 3건
- 2019.10.23 :: Springboot - java.lang.IllegalArgumentException: 'Content-Type' cannot contain wildcard type '*'
- 2019.06.15 :: Springboot - Logback 설정 방법 !(logback-spring.xml) 1
- 2019.02.21 :: Springboot - CommandLineRunner(커맨드라인러너)
응답으로 나가는 Object에 getter가 존재하지 않아서 Response Content-type을 추론하지 못했다. 그래서 필터 단에서 임의로 DefaultMediaType으로 */*? * 로 넣어버리지만 사실 Content-Type에 wildCard는 들어가지 못한다. 즉, 예외발생!
'Web > Spring' 카테고리의 다른 글
Springboot - Webflux WebClient Cancelled가 나는 상황("The subscription was cancelled") (0) | 2020.02.20 |
---|---|
Spring - Spring Data Reactive mongo MongoCustomConversions 예제 (0) | 2020.02.03 |
Spring - ResponseBodyAdvice를 이용한 응답값 가공! (0) | 2019.10.18 |
Springboot - Custom Annotation(커스텀 어노테이션)과 Interceptor를 이용한 컨트롤러 인증.(컨트롤러 전처리, 후처리) (0) | 2019.10.12 |
Springboot - Springboot MVC Test(JUnit) (0) | 2019.10.10 |
오늘 포스팅할 내용은 개발 단계에서 없어서는 안되는 로그에 관한 포스팅입니다. 매번 sysout으로 로그를 찍는 것은 바보 같이 리소스를 낭비하는 짓이라는 것은 누구나 다 알고 계실겁니다. 저는 별소 lombok을 즐겨 사용하기에 @Slfj4 어노테이션을 자주 사용하게 됩니다. 하지만 이번에는 단순 콘솔에서만 출력하는 것이 아니라, 일자별 로그파일을 떨구어주는 설정파일에 대해 알아볼 것입니다. 바로 예제로 들어가겠습니다.(로그사용법에 대해서는 다루지 않습니다.)
참고로 Logback은 slf4j의 구현체이자 스프링 부트의 기본 로그 객체입니다. 기본으로 classpath에서 스프링부트가 읽어가는 파일 이름은 logback-spring.xml입니다. 물론 설정 파일명을 변경하실 수도 있습니다.
1
2
|
#logging config
logging.config=classpath:logging-config.xml
|
cs |
저는 기본 설정파일명을 사용하지 않을 것이기 때문에 application.properties에 로깅 설정 파일명을 명시해줍니다.
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
|
<configuration>
<!-- Created By yeoseong_yoon -->
<!-- 로그 경로 변수 선언 -->
<property name="LOG_DIR" value="${user.home}/logs/app" />
<property name="LOG_PATH" value="${LOG_DIR}/app.log"/>
<!-- Console Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%-5level %d{HH:mm:ss.SSS} [%thread %F:%L] %method - %msg%n
</pattern>
</encoder>
</appender>
<!-- Rolling File Appender -->
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 파일 경로 -->
<file>${LOG_PATH}</file>
<!-- 출력패턴 -->
<encoder>
<pattern>%-5level %d{HH:mm:ss.SSS} [%thread %F:%L] %method - %msg%n</pattern>
</encoder>
<!-- Rolling 정책 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- .gz,.zip 등을 넣으면 자동으로 일자별 로그파일 압축 -->
<fileNamePattern>${LOG_DIR}/app_%d{yyyy-MM-dd}_%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 파일당 최고 용량 10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 일자별 로그파일 최대 보관주기(일단위)
만약 해당 설정일 이상된 파일은 자동으로 제거-->
<maxHistory>60</maxHistory>
</rollingPolicy>
</appender>
<logger name="애플리케이션패키지명(ex com.web.spring)" level="INFO"/>
<root level="INFO"> <!-- DEBUG -->
<appender-ref ref="ROLLING_FILE"/>
</root>
</configuration>
|
cs |
우선은 <property>를 이용하여 전역으로 사용할 변수명을 지정해줍니다. 이 설정파일에서는 로그파일의 경로, 로그파일 Full Path를 변수에 할당하였습니다. 그다음 중요한 설정인 <appender> 설정입니다. 로그 파일의 출력 형식을 지정해주는 설정이라고 보시면 됩니다. 사실 설정의 핵심중 하나입니다. 현재 설정에서는 console,rollingfile appender를 지정해주었습니다.
Appender 종류
이름 | 설명 |
ConsoleAppender | 콘솔에 로그를 찍음 |
FileAppender | 파일에 로그를 찍음(하나의 파일에 로그를 계속 누적해서 찍음) |
RollingFileAppender | 여러개의 파일을 순회하면서 로그를 찍음 |
SMTPAppender | 로그를 메일에 찍어 보냄 |
DBAppender | DB에 로그를 찍음 |
기타 SocketAppender, SSLSocketAppender... |
패턴에 사용되는 요소
- 1. %Logger{length}
- - Logger name을 축약할 수 있다. {length}는 최대 자리 수
- 2. %thread
- - 현재 Thread 이름
- 3. %-5level
- - 로그 레벨, -5는 출력의 고정폭 값
- 4. %msg
- - 로그 메시지 (=%message)
- 5. %n
- - new line
- 6. ${PID:-}
- - 프로세스 아이디
- 기타
- %d : 로그 기록시간
- %p : 로깅 레벨
- %F : 로깅이 발생한 프로그램 파일명
- %M : 로깅일 발생한 메소드의 이름
- %l : 로깅이 발생한 호출지의 정보
- %L : 로깅이 발생한 호출지의 라인 수
- %t : 쓰레드 명
- %c : 로깅이 발생한 카테고리
- %C : 로깅이 발생한 클래스 명
- %m : 로그 메시지
- %r : 애플리케이션 시작 이후부터 로깅이 발생한 시점까지의 시간
위에 설정에서 하나 짚고 넘어갈 것이 있다면 RollingAppender의 <file>과 <fileNamePattern>이다. 일자별 로그파일을 찍기 위해 버퍼가 되는 파일이고 후자는 일자별 로그파일의 이름 패턴을 넣어주는 것이다.
이상 정말 간단한 Logback 설정방법을 다루어보았다. 이것보다 많은 설정들이 있을 것이다. 하지만 필자로 깊게 알지못하기에 간단한 사용법만 다루었다. 하지만 하나 중요한 사실은 로그를 남기는 것도 좋지만, 적정 레벨의 선택 그리고 포맷이다. 필자가 프로젝트를 하며 ELK를 이용하여 로그를 중앙 집중식으로 관리를 하게되었는데, 정규식패턴식과 같은 것으로 로그파일을 필터링 할 상황이 생겼다. 만약 구조화된 로그 출력이라면 정규식으로 필터링 걸기가 편할 것이지만 구조화되지 않고 애플리케이션마다 출력하는 패턴이 다르다면 필터링 하는 작업도 쉽지 않을 것이다.
'Web > Spring' 카테고리의 다른 글
Spring - Field vs Constructor vs Setter Injection 그리고 순환참조(Circular Reference) (3) | 2019.08.17 |
---|---|
Springboot - DB Datasource 암호화/복호화(application.properties) (0) | 2019.08.05 |
Spring - RestTemplate Connection Pooling (0) | 2019.06.13 |
Spring - JSON to Object(Object to JSON) Converting Gson ! (0) | 2019.05.30 |
Spring - ModelMapper란? (2) | 2019.04.10 |
Springboot - CommandLineRunner(커맨드라인러너)
Springboot에서 서버 구동 시점에 초기화작업으로 무엇인가를 넣고 싶다면 사용할 수 있는 방법 중 하나가
CommandLineRunner인터페이스를 상속받는 것이다.
@SpringBootApplication 어노테이션이 붙어있는 부트구동 클래스에 CommandLineRunner를 implements
하고 run(String... strings)를 Override한다.
그리고 해당 run()에 애플리케이션의 초기작업(빈등록 과정 등등)이후 실행할 로직을 작성해주면 된다.
예제 코드는 항공편 예약서비스 예제인데, 애플리케이션 구동 시점에 예약가능한
비행편을 알아보기위하여 검색 마이크로서비스 애플리케이션에 초기데이터를
삽입하는 코드이다.
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 | @SpringBootApplication public class Application implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(Application.class); @Autowired private FlightRepository flightRepository; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(String... strings) throws Exception { List<Flight> flights = new ArrayList<>(); flights.add(new Flight("BF100", "SEA","SFO","22-JAN-18",new Fares("100", "USD"),new Inventory(100))); flights.add(new Flight("BF101", "NYC","SFO","22-JAN-18",new Fares("101", "USD"),new Inventory(100))); flights.add(new Flight("BF105", "NYC","SFO","22-JAN-18",new Fares("105", "USD"),new Inventory(100))); flights.add(new Flight("BF106", "NYC","SFO","22-JAN-18",new Fares("106", "USD"),new Inventory(100))); flights.add(new Flight("BF102", "CHI","SFO","22-JAN-18",new Fares("102", "USD"),new Inventory(100))); flights.add(new Flight("BF103", "HOU","SFO","22-JAN-18",new Fares("103", "USD"),new Inventory(100))); flights.add(new Flight("BF104", "LAX","SFO","22-JAN-18",new Fares("104", "USD"),new Inventory(100))); flightRepository.saveAll(flights); logger.info("Looking to load flights..."); for (Flight flight : flightRepository.findByOriginAndDestinationAndFlightDate("NYC", "SFO", "22-JAN-18")) { logger.info(flight.toString()); } } } | cs |
만약 애플리케이션 구동 순서에 선후가 존재한다면 후행 애플리케이션에 위와같이 run()을 오버라이드하여
선행 애플리케이션에 Health Check등을 하는 로직을 넣어도 괜찮은 방법이 될 것 같다.
'Web > Spring' 카테고리의 다른 글
Spring - Springboot GenericController(제네릭컨트롤러), 컨트롤러 추상화 (0) | 2019.03.22 |
---|---|
Spring - ApplicationContext,ApplicationContextAware, 빈이 아닌 객체에 빈주입할때! (0) | 2019.02.25 |
Springframework QueryParameter 숨기며 뷰 리턴하는 방법 (0) | 2018.10.23 |
Springframework - RestTemplate(Restful) (0) | 2018.10.11 |
간단한 springframework JdbcTemplate 예제 (0) | 2018.10.05 |