Skip to content

Commit d03da84

Browse files
chaewon121dooboocookie
authored andcommitted
[BE] refactor: 로깅 구체화 하기 (#318)
* feat: 로그 필터 구현 * fix: application prod를 local로 수정 * feat: logback gradle 의존성 추가 * feat: 기존 로깅 파일 삭제 * feat: logback xml 파일 설정 * feat: 로그 필터 구현 * feat: mdc 필터 구현 * feat: 필터 빈등록 * feat: exceptionHandler 수정 * feat: 깃허브 설정 * refactor: mdc 이넘 추가 * refactor: info 로그 출력 message추가 * refactor: 추가 메서드 삭제 * refactor: 사용하지 않는 상수 삭제 * chore: 쿼리 튜닝 및 성능 조회를 위한 변경사항 * chore: 쿼리 정보 로그 삭제 * feat: 로깅 추가 (#359) * feat: 로그 필터 구현 * fix: application prod를 local로 수정 * feat: logback gradle 의존성 추가 * feat: 기존 로깅 파일 삭제 * feat: logback xml 파일 설정 * feat: 로그 필터 구현 * feat: mdc 필터 구현 * feat: 필터 빈등록 * feat: exceptionHandler 수정 * feat: 깃허브 설정 * refactor: mdc 이넘 추가 * refactor: info 로그 출력 message추가 * refactor: 추가 메서드 삭제 * refactor: 사용하지 않는 상수 삭제 * chore: 쿼리 튜닝 및 성능 조회를 위한 변경사항 * chore: 쿼리 정보 로그 삭제 --------- Co-authored-by: chaewon121 <[email protected]> * fix: 워크플로우 수정 * hotfix: PlayerRepository.findAll() 호출 시 N+1 문제 수정 (#360) * refactor: Player의 Member 필드 지연로딩으로 변경 * refactor: PlayerRepository.findAll() Fetch Join 진행 * test: 지연 로딩으로 인한 테스트 에러 임시 수정 * refactor: 코드컨벤션 젹용 * refactor: 날짜 수정 * refactor: mdc 필터 제거 * refactor: 사용하지 않는 mdc토큰 제거 * refactor: 로깅 전략 변경에 따른 코드 수정 * refactor: xml파일에서 mdc 출력 삭제 * refactor: 환경분리 및 패턴 수정 * fix: 환경분리 오류 수정 * refactor: mdc 요소 추가 * chore: 워크플로우 수정 * fix: 트렌젝션 테스트에 추가 * fix: 에러로그 출력 오류 수 * refactor: info로그 수정 * refactor: warn로그 수정 * refactor: error로그 수정 * refactor: 사용하지 않는 enum 삭제 * refactor: 주석 제거 * refactor: 패키지 이동 * refactor: 사용하지 않는 코드 제거 * refactor: warn 레벨 info 로 수정 --------- Co-authored-by: dooboocookie <[email protected]> Co-authored-by: dooboocookie <[email protected]>
1 parent 573c7e8 commit d03da84

28 files changed

+487
-176
lines changed

.idea/2023-naaga.iml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/workspace.xml

Lines changed: 116 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ dependencies {
2626
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
2727
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
2828
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
29+
30+
implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5'
31+
implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5'
32+
implementation 'net.logstash.logback:logstash-logback-encoder:6.1'
2933
}
3034

3135
tasks.named('test') {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.now.naaga.common.config;
2+
3+
import com.now.naaga.common.presentation.LogFilter;
4+
import com.now.naaga.common.presentation.QueryCounter;
5+
import org.springframework.boot.web.servlet.FilterRegistrationBean;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
9+
@Configuration
10+
public class FilterConfig {
11+
12+
private final QueryCounter queryCounter;
13+
14+
public FilterConfig(final QueryCounter queryCounter) {
15+
this.queryCounter = queryCounter;
16+
}
17+
18+
@Bean
19+
public FilterRegistrationBean<LogFilter> logFilter() {
20+
final LogFilter logFilter = new LogFilter(queryCounter);
21+
return new FilterRegistrationBean<>(logFilter);
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.now.naaga.common.config;
2+
3+
import com.now.naaga.common.presentation.QueryInspector;
4+
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR;
9+
10+
@Configuration
11+
public class HibernateConfig {
12+
13+
private final QueryInspector queryInspector;
14+
15+
public HibernateConfig(final QueryInspector queryInspector) {
16+
this.queryInspector = queryInspector;
17+
}
18+
19+
@Bean
20+
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
21+
return hibernateProperties -> hibernateProperties.put(STATEMENT_INSPECTOR, queryInspector);
22+
}
23+
}

backend/src/main/java/com/now/naaga/common/exception/ControllerExceptionHandler.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.now.naaga.common.exception;
22

3-
import jakarta.persistence.criteria.CriteriaBuilder;
43
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
65
import org.springframework.http.HttpStatus;
@@ -20,46 +19,41 @@ public class ControllerExceptionHandler {
2019
public ResponseEntity<ExceptionResponse> handleBaseException(final BaseException e) {
2120
final BaseExceptionType baseExceptionType = e.exceptionType();
2221
final ExceptionResponse exceptionResponse = new ExceptionResponse(baseExceptionType.errorCode(), baseExceptionType.errorMessage());
23-
log.warn("error = {}", exceptionResponse, e);
22+
23+
log.info("error = {}", exceptionResponse);
24+
2425
return ResponseEntity.status(baseExceptionType.httpStatus()).body(exceptionResponse);
2526
}
2627

2728
@ExceptionHandler({
2829
HttpMessageNotReadableException.class,
2930
MethodArgumentNotValidException.class,
30-
HttpMediaTypeNotSupportedException.class
31-
})
31+
HttpMediaTypeNotSupportedException.class})
3232
public ResponseEntity<ExceptionResponse> handleTypeMismatchException(final Exception e) {
3333
final CommonExceptionType commonExceptionType = CommonExceptionType.INVALID_REQUEST_BODY;
3434
final ExceptionResponse exceptionResponse = new ExceptionResponse(commonExceptionType.errorCode(), commonExceptionType.errorMessage());
35-
log.warn("error = {}", exceptionResponse, e);
35+
36+
log.info("error = {}", exceptionResponse);
37+
3638
return ResponseEntity.status(commonExceptionType.httpStatus()).body(exceptionResponse);
3739
}
3840

3941
@ExceptionHandler(InternalException.class)
40-
public ResponseEntity<ExceptionResponse> handleInternalException(final InternalException e){
42+
public ResponseEntity<ExceptionResponse> handleInternalException(final InternalException e) {
4143
final BaseExceptionType internalExceptionType = e.exceptionType();
4244

43-
// log.error("errorCode = {} \n message = {}",
44-
// internalExceptionType.errorCode(),
45-
// internalExceptionType.errorMessage());
46-
47-
log.error("errorCode = {} \n message = {} \n error = {}",
48-
internalExceptionType.errorCode(),
49-
internalExceptionType.errorMessage(),
50-
e.getMessage() , e);
45+
log.error(e.getMessage(), e);
5146

5247
final ExceptionResponse exceptionResponse = new ExceptionResponse(10000, "예기치 못한 오류입니다");
5348
return ResponseEntity.status(internalExceptionType.httpStatus())
5449
.body(exceptionResponse);
5550
}
5651

5752
@ExceptionHandler(Exception.class)
58-
public ResponseEntity<ExceptionResponse> handleException(final Exception e){
59-
log.error("error = {}"+ e.getMessage() , e);
53+
public ResponseEntity<ExceptionResponse> handleException(final Exception e) {
54+
log.error(e.getMessage(), e);
6055

6156
final ExceptionResponse exceptionResponse = new ExceptionResponse(10000, "예기치 못한 오류입니다");
62-
e.printStackTrace();
6357
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
6458
.body(exceptionResponse);
6559
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.now.naaga.common.presentation;
2+
3+
import jakarta.servlet.*;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.slf4j.MDC;
8+
9+
import java.io.IOException;
10+
import java.util.UUID;
11+
12+
import static com.now.naaga.common.presentation.MdcToken.*;
13+
14+
public class LogFilter implements Filter {
15+
16+
private static final String LOG_FORMAT = "uri: {}, method: {}, time: {}ms, queryCount: {}";
17+
18+
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
19+
private final QueryCounter queryCounter;
20+
21+
public LogFilter(final QueryCounter queryCounter) {
22+
this.queryCounter = queryCounter;
23+
}
24+
25+
@Override
26+
public void doFilter(final ServletRequest request,
27+
final ServletResponse response,
28+
final FilterChain chain)
29+
throws IOException, ServletException {
30+
queryCounter.init();
31+
32+
final long start = System.currentTimeMillis();
33+
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
34+
MDC.put(REQUEST_ID.getKey(), UUID.randomUUID().toString());
35+
36+
chain.doFilter(request, response);
37+
38+
final int queryCount = queryCounter.count();
39+
log(start, queryCount, httpServletRequest);
40+
queryCounter.close();
41+
MDC.clear();
42+
}
43+
44+
private void log(final long start,
45+
final int queryCount,
46+
final HttpServletRequest httpServletRequest) {
47+
final long end = System.currentTimeMillis();
48+
final long time = end - start;
49+
log.info(LOG_FORMAT, httpServletRequest.getRequestURI(), httpServletRequest.getMethod(), time, queryCount);
50+
}
51+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.now.naaga.common.presentation;
2+
3+
public enum MdcToken {
4+
5+
REQUEST_ID("request_id")
6+
;
7+
8+
private final String key;
9+
10+
MdcToken(final String key) {
11+
this.key = key;
12+
}
13+
14+
public String getKey() {
15+
return key;
16+
}
17+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.now.naaga.common.presentation;
2+
3+
import org.springframework.stereotype.Component;
4+
5+
@Component
6+
public class QueryCounter {
7+
8+
private static final int INITIAL_VALUE = 0;
9+
10+
private final ThreadLocal<Integer> count = new ThreadLocal<>();
11+
12+
public void increase() {
13+
if (count.get() == null) {
14+
init();
15+
}
16+
count.set(count.get() + 1);
17+
}
18+
19+
public void init() {
20+
count.set(INITIAL_VALUE);
21+
}
22+
23+
public int count() {
24+
return count.get();
25+
}
26+
27+
public void close() {
28+
count.remove();
29+
}
30+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.now.naaga.common.presentation;
2+
3+
import org.hibernate.resource.jdbc.spi.StatementInspector;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.web.context.request.RequestContextHolder;
8+
9+
import java.util.Objects;
10+
11+
@Component
12+
public class QueryInspector implements StatementInspector {
13+
14+
private final QueryCounter queryCounter;
15+
16+
public QueryInspector(final QueryCounter queryCounter) {
17+
this.queryCounter = queryCounter;
18+
}
19+
20+
@Override
21+
public String inspect(final String sql) {
22+
if (isInRequestScope()) {
23+
queryCounter.increase();
24+
}
25+
return sql;
26+
}
27+
28+
private boolean isInRequestScope() {
29+
return Objects.nonNull(RequestContextHolder.getRequestAttributes());
30+
}
31+
}

0 commit comments

Comments
 (0)