로깅 간단히 알아보기
스프링 부트 로깅 라이브러리
- SLF4J
- Logback
- 로그 라이브러리는 Logback, Log4J, Log4J2 등등 수 많은 라이브러리가 있는데, 그것을 통합해서 인터페이스로 제공하는 것이 바로 SLF4J 라이브러리다.
- 즉, SLF4J는 인터페이스이고 그 구현체로 Logback 같은 로그 라이브러리를 선택하면 된다. 실무에서는 스프링 부트가 기본으로 제공하는 Logback을 대부분 사용한다.
로그 선언
private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class);
@Slf4j : 롬복 사용 가능
LogTestController (http://localhost:8080/log-test)
@Slf4j
@RestController #"ok"을 바로 반환하여서 출력하게끔 한다
public class LogTestController {
// private final Logger log = LoggerFactory.getLogger(getClass());
@RequestMapping("/log-test")
public String logTest() {
String name = "Spring";
log.trace("trace log={}", name);
log.debug("debug log={}", name);
log.info(" info log={}", name);
log.warn(" warn log={}", name);
log.error("error log={}", name);
//로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
log.debug("String concat log=" + name);
return "ok";
}
}
@RestController
- @Controller 는 반환 값이 String 이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.
- @RestController 는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다. 따라서 실행 결과로 ok 메세지를 받을 수 있다. @ResponseBody 와 관련이 있는데, 뒤에서 더 자세히 설명한다.
로그 레벨
- TRACE > DEBUG > INFO > WARN > ERROR
- 개발 서버는 debug 출력, 운영 서버는 info 출력
로그 레벨 설정
#application.properties 파일에 설정하기
#전체 로그 레벨 설정(기본 info)
logging.level.root=info
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug
올바른 로그 사용법
- log.debug("data=" + data) : 로그 출력 레벨을 info로 설정해도 해당 코드에 있는 "data="+data가 실제 실행이 되기에 의미없는 연산이 발생한다.
- log.debug("data={}", data) : 의미없는 연산이 발생하지 않으므로 이렇게 사용하자.
로그 사용시 장점
- 쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
- 로그 레벨에 따라 로그를 상황에 맞게 조절할 수 있다.
- 파일이나 네트워크 등, 로그를 별도의 위치에 남길 수 있다.
- 성능도 일반 System.out보다 좋기에 실무에서는 꼭 로그를 사용해야 한다.
- private: 다른 클래스에서 가로채 사용하지 못하도록
- static: 인스턴스당 하나만 필요하므로, 또한 직렬화를 피하기 위해
- final: 변경될 일이 없으므로
요청 매핑
@RestController
public class MappingController {
private Logger log = LoggerFactory.getLogger(getClass());
/*
기본 요청, 둘다 허용 /hello-basic, /hello-basic/
HTTP 메서드 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
*/
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("helloBasic");
return "ok";
}
}
@RequestMapping("/hello-basic")
- /hello-basic URL 호출이 오면 이 메서드가 실행되도록 매핑한다. 대부분의 속성을 배열[] 로 제공하므로 다중 설정이 가능하다. @RequestMapping({"/hello-basic","/hello-go"})
- method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다. 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
이런 경우엔 다른 URL 이지만, 스프링에서는 같은 요청으로 매핑한다.
- URL 요청: /hello-basic , /hello-basic/
- 매핑: /hello-basic
HTTP 메서드 매핑
#RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, ...
@RequestMapping("/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
- method 특정 HTTP 메서드 요청만 허용
- 만약 여기에 POST 요청을 하면 스프링 MVC는 HTTP 405 상태코드(Method Not Allowed)를 반환한다.\
HTTP 메서드 매핑 축약
@GetMapping("/mapping-get-v2")
public String mappingGetV2() {
log.info("mapping-get-v2");
return "ok";
}
- 훨씬 직관적이므로 이렇게 사용하자.
- @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping
PathVariable (경로 변수)
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId={}", data);
return "ok";
}
- 실행: http://localhost:8080/mapping/userA
- @PathVariable의 이름과 파라미터 이름이 같으면 생략 가능하다.
- @PathVariable("userId") String userId -> @PathVariable String userId
- 최근 HTTP API는 다음과 같이 리소스 경로에 식별자를 넣는 스타일을 선호한다.
- /mapping/userA, /users/1
PathVariable 사용 - 다중
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
log.info("mappingPath userId={}, orderId={}", userId, orderId);
return "ok";
}
- 실행: http://localhost:8080/mapping/users/userA/orders/100
특정 파라미터 조건 매핑
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
log.info("mappingParam");
return "ok";
}
- 실행: http://localhost:8080/mapping-param?mode=debug
- 파라미터에 특정 값이 포함되어야 동작할 수 있다. 여기서는 mode=debug가 포함되어야 한다.
특정 헤더 조건 매핑
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
log.info("mappingHeader");
return "ok";
}
- 실행: Postman으로 테스트해야한다.
- 파라미터 매핑과 비슷하지만, HTTP 헤더를 사용한다.
- 헤더이름: mode, 헤더값: debug를 설정해줘야 동작한다.
미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
log.info("mappingConsumes");
return "ok";
}
- HTTP 헤더의 Content-Type이 application/json 이어야 동작한다.
- 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)을 반환한다.
미디어 타입 조건 매핑 - HTTP 요청 Accept, produce
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
log.info("mappingProduces");
return "ok";
}
- HTTP 헤더의 Accept가 text/html 이어야 동작한다.
- 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환한다.
요청 매핑 - API
회원관리 API
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
@GetMapping #회원목록 조회
public String users() {
return "get users";
}
@PostMapping #추가
public String addUser() {
return "post user";
}
@GetMapping("/{userId}") #조회
public String findUser(@PathVariable String userId) {
return "get userId=" + userId;
}
@PatchMapping("/{userId}") #수정
public String updateUser(@PathVariable String userId) {
return "update userId=" + userId;
}
@DeleteMapping("/{userId}") #삭제
public String deleteUser(@PathVariable String userId) {
return "delete userId=" + userId;
}
}
- 회원 목록 조회: GET /users
- 회원 등록: POST /users
- 회원 조회: GET /users/{userId}
- 회원 수정: PATCH /users/{userId}
- 회원 삭제: DELETE /users/{userId}
HTTP 요청 - 기본, 헤더 조회
@Slf4j
@RestController
public class RequestHeaderController {
@RequestMapping("/headers")
public String headers(HttpServletRequest request,
HttpServletResponse response,
HttpMethod httpMethod,
Locale locale,
@RequestHeader MultiValueMap<String, String> headerMap,
@RequestHeader("host") String host,
@CookieValue(value = "myCookie", required = false) String cookie
) {
log.info("request={}", request);
log.info("response={}", response);
log.info("httpMethod={}", httpMethod);
log.info("locale={}", locale);
log.info("headerMap={}", headerMap);
log.info("header host={}", host);
log.info("myCookie={}", cookie);
return "ok";
}
}
- HttpMethod : HTTP 메서드를 조회한다. org.springframework.http.HttpMethod
- Locale : Locale 정보를 조회한다.
- @RequestHeader MultiValueMap headerMap : 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.
- @RequestHeader("host") String host : 특정 HTTP 헤더를 조회한다.
- @CookieValue(value = "myCookie", required = false) String cookie : 특정 쿠키를 조회한다.
'스프링' 카테고리의 다른 글
[스프링 MVC 1편] 스프링 MVC - 기본 기능 (3) (0) | 2022.06.29 |
---|---|
[스프링 MVC 1편] 스프링 MVC - 기본 기능 (2) (0) | 2022.06.24 |
[스프링 핵심 원리] 빈 스코프 (2) (0) | 2022.06.22 |
[스프링 핵심 원리] 빈 스코프 (1) (0) | 2022.06.22 |
[스프링 핵심 원리] 빈 생명주기 콜백 (0) | 2022.06.20 |