인프런/스프링 MVC 1편

8)스프링 MVC - 기본기능, 로깅(logging)

backend dev 2023. 1. 19.

초기설정

필수 체크
gradle 보다 인텔리제이가 더 빠르다고 한다.

스프링부트 application 실행해서 동작 테스트

잘 동작한다.


 

 

서버 기본주소에서 동작하는 welcome page


로깅(logging) 간단히 알아보기

스프링부트를 생성하면 자동으로 추가되는 스프링부트스타터 안에 스프링부트 스타터 로깅이라는 라이브러리가 있고 

그 안에 SLF4J와 Logback있는걸 확인할 수 있었다.

Logger를 임포트할때 slf4j로 임포트해줘야한다. 인터페이스를 slf4j로 쓸것이니까.

slf4j가 다른 로그 라이브러리를 통합해서 만든 인터페이스 역할을 하는 라이브러리이다.

 

LogTestController

//@Controller 어노테이션을 사용하고, Mapping 메소드에서 String을 반환하면 뷰 이름으로 인식한다.( 받은 문자를 논리 뷰 이름으로 인식하여 뷰 리졸버를 이용하여 뷰를 생성하려고할것이다)
@RestController// @RestController를 사용했을때 String을 반환하면, 그냥 String이 바로 반환된다. (http 응답메시지 바디에 반환된 문자를 넣고 반환해버린다) (rest api의 그 rest이다) ,테스트용으로는 편리
public class LogTestController {
    private final Logger log = LoggerFactory.getLogger(getClass());
    //매개 변수로 전달된 클래스에 해당하는 이름의 로거를 반환합니다, getClass()로 클래스정보를 얻고, LoggerFactory.getLogger를 통해 로거를 받아온다.

    @GetMapping("/log-test")
    public String logTest() {
        String name = "Spring";
//        System.out.println("name = " + name); 과거에는 이런식으로 로그를 찍어봤을것이다.
        log.info(" info log = {}", name);

        return "OK";
    }
}

 

LoggerFactory는 로거를 생성하는 유틸리티 클래스
LoggerFactory의 getLogger()를 이용하여  클래스정보를 파라미터로 주고 로거를 반환 받는다.

 

Java Platform SE 8

 

docs.oracle.com

자바 공식문서를 참고하였다.

실행결과 : @RestController 어노테이션이 있어서, String 반환이 http응답메시지의 body에 담겨 응답됬기에 저런 결과를 보인다.

log.info(" info log = {}", name);

로 인한 결과

왼쪽에서 부터 순서대로

시간 ,로그레벨, 프로세스아이디 , [작업을 실행한 쓰레드 정보] ,실행된클래스정보(로거이름),추가적으로 적은 메시지출력

메시지에 {}가 있으면 오른쪽의 변수로 치환된다. 

 

@GetMapping("/log-test")
    public String logTest() {
        String name = "Spring";
        String name2 = "Spring2";
//        System.out.println("name = " + name); 과거에는 이런식으로 로그를 찍어봤을것이다.
        log.trace("trace log={}, {}", name, name2);
        log.debug("debug log={}, {}", name, name2);
        log.info("info log={}", name);
        log.warn("warn log={}, {}", name, name2);
        log.error("error log={}, {}", name, name2);

        return "OK";
    }

다음과 같이 로그레벨들을 더 추가해서 로그를 찍어본다.

로그레벨이 trace, debug인 경우는 보이지 않는다.

 

만약 로컬에서 개발을 하는중이고 모든 로그레벨을 보고싶다면

application.properties에서 로그레벨 설정을 해주면 된다.

#hello.springmvc 패키지와 그 하위 패키지의 로그 레벨 설정
logging.level.hello.springmvc = trace

다음과 같이 로그레벨을 설정해준다. ( 어떤 로그레벨부터 볼것인지 설정, 해당 로그레벨~ 상위레벨 로그까지 다 로깅한다)

 

로그레벨은 치명적인 정도에 따른 순서가 있다. 

1. TRACE -> debug보다 좀 더 자세하게 코드를 추적할때 사용한다.

2. DEBUG -> 프로그램을 디버깅하기 위한 정보를 나타낸다.

3. INFO -> 서비스 시작 및 중지같은 상태변경과 같은 정보성 메시지를 나타낸다.

4. WARN -> 프로그램의 실행에는 문제가 없지만, 향후 시스템 에러의 원인이 될 수 있는 경고성 메시지를 나타낸다. 

5. ERROR -> 프로그램이 하나 이상의 기능이 동작하지않아 문제가 발생한 상태 ( 요청 처리중 문제가 발생한 경우)

6. FATAL -> 아주 심각한 오류 발생으로 어플리케이션이 동작하지 않는 상태

 

trace가 레벨이 낮고 fatal가면서 레벨이 높다.

 

그리고 다시 실행해보면

모든 로그레벨의 로그가 찍힌다. ( trace레벨 로그부터 상위 로그레벨 로그까지 모두 보인다.)

 

만약 debug레벨부터 보고 싶다면

logging.level.hello.springmvc = debug

수정해준다.

디버그와 그 하위 로그레벨의 로그만 보인다.

 

개발서버는 DEBUG정도로 로그레벨을 설정해두  

로컬에는 TRACE 또는 DEBUG로 로그레벨을 설정해두고

(자세하게 보면서 개발을해야하므로, 디버깅하면서 로깅 해야할수 있으므로)

운영서버에는 INFO레벨로 설정해둔다. ( 트래픽이 워낙 많기에 중요 정보만 남긴다.)

 

기본 로그레벨

application.properties에서 로그레벨을 설정하지않았을때 INFO 로그레벨 부터 출력이 됬다.

그 뜻은 기본 로그레벨이 INFO라는것이다.

#전체 로그 레벨 설정(기본 info)
logging.level.root=info

이런식으로 자동으로 설정되어있는것이다.  (루트는 프로젝트 전체를 의미)

 

logging.level.root = debug

로 바꾸고 스프링을 다시 켜보면

수많은 로그가 찍히게 된다. 라이브러리 부터 시작해서 스프링설정 등, 로그레벨을 DEBUG로 로깅하도록 이미 설정 되어있기 때문이다. 

 

결론은 내가 원하는 부분만 로그레벨을 수정하여 로깅되게끔 하자

 

위에서 한 방법말고 로거를 가져오는 2가지 방법이 더 있다.

private final Logger log = LoggerFactory.getLogger(getClass());

getClass()로 클래스정보를 넘기는방법

private final Logger log = LoggerFactory.getLogger(LogTestController.class);

그냥 클래스명.class로 넘기는 방법

 

그리고 어노테이션(롬복)을 사용한 편한방법

편하게 로깅하기

@Slf4j
@RestController
public class LogTestController {

    @GetMapping("/log-test")
    public String logTest() {
        String name = "Spring";
        String name2 = "Spring2";

        log.trace("trace log={}, {}", name, name2);
        log.debug("debug log={}, {}", name, name2);
        log.info("info log={}", name);
        log.warn("warn log={}, {}", name, name2);
        log.error("error log={}, {}", name, name2);

        return "OK";
    }
}

@Slf4j 어노테이션을 사용하면 귀찮게 넣던

private final Logger log = LoggerFactory.getLogger(getClass());

이 코드를 자동으로 넣어주게 된다.

 

올바른 로그 사용법

로그를 찍을때는 다음과 같은 방법을 사용해야한다.

log.trace("trace log={}, {}", name, name2);
log.debug("debug log={}, {}", name, name2);
log.info("info log={}", name);
log.warn("warn log={}, {}", name, name2);
log.error("error log={}, {}", name, name2);

{}를 이용해서 변수를 치환하게끔 해야한다.

 

log.trace("trace my log = " + name);

이런식으로 해도 문자열 합치기가 되서 로그메시지는 잘 출력될것이다.

하지만 자바는 로그가 출력되기전에 저 문자열을 합치는 연산을 해두고 가지고있다 

 

만약에 저 로그가 있는 클래스의 패키지의 로그레벨이 DEBUG라면 

trace 로그는 찍히지않을것이다.  하지만 자바는 미리 문자열을 합치는 연산을 하기때문에 쓸모없는 리소스를 사용하게되는것이다. trace로그를 찍는데 다 저런식으로 로그메시지를 구성한다면 엄청난 리소스 낭비가 발생할것이다.

 

그러므로 {}를 사용한다 ( {}를 사용하면 해당 로그가 찍힐때 연산)

로그에 대해서 더 자세한 내용은 slf4j, logback을 검색해보자.
SLF4J - http://www.slf4j.org
Logback http://logback.qos.ch
스프링 부트가 제공하는 로그 기능은 다음을 참고하자.
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.logging

댓글