Web/Spring 2019. 10. 23. 21:33

응답으로 나가는 Object에 getter가 존재하지 않아서 Response Content-type을 추론하지 못했다. 그래서 필터 단에서 임의로 DefaultMediaType으로 */*? * 로 넣어버리지만 사실 Content-Type에 wildCard는 들어가지 못한다. 즉, 예외발생!

posted by 여성게
:
Web/Spring 2019. 6. 15. 21:57

 

오늘 포스팅할 내용은 개발 단계에서 없어서는 안되는 로그에 관한 포스팅입니다. 매번 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를 이용하여 로그를 중앙 집중식으로 관리를 하게되었는데, 정규식패턴식과 같은 것으로 로그파일을 필터링 할 상황이 생겼다. 만약 구조화된 로그 출력이라면 정규식으로 필터링 걸기가 편할 것이지만 구조화되지 않고 애플리케이션마다 출력하는 패턴이 다르다면 필터링 하는 작업도 쉽지 않을 것이다.

posted by 여성게
:
Web/Spring 2019. 2. 21. 22:14

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등을 하는 로직을 넣어도 괜찮은 방법이 될 것 같다.

posted by 여성게
: