Skip to content

Commit

Permalink
Fix: ExceptionRestHandler 로깅을 ErrorType에 따른 레벨로 수정 (#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaewon-pro authored Oct 16, 2024
1 parent 9114a4b commit 3aa6cbd
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 29 deletions.
55 changes: 32 additions & 23 deletions src/main/java/com/dnd/runus/global/exception/type/ErrorType.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.experimental.Accessors;
import org.springframework.http.HttpStatus;

import static com.dnd.runus.global.exception.type.ErrorType.Level.*;
import static lombok.AccessLevel.PRIVATE;
import static org.springframework.http.HttpStatus.*;

Expand All @@ -13,43 +14,51 @@
@RequiredArgsConstructor(access = PRIVATE)
public enum ErrorType {
// WebErrorType
UNHANDLED_EXCEPTION(INTERNAL_SERVER_ERROR, "WEB_001", "직접적으로 처리되지 않은 예외, 문의해주세요"),
FAILED_VALIDATION(BAD_REQUEST, "WEB_002", "Request 요청에서 올바르지 않은 값이 있습니다"),
FAILED_PARSING(BAD_REQUEST, "WEB_003", "Request JSON body를 파싱하지 못했습니다"),
UNSUPPORTED_API(BAD_REQUEST, "WEB_004", "지원하지 않는 API입니다"),
COOKIE_NOT_FOND(BAD_REQUEST, "WEB_005", "요청에 쿠키가 필요합니다"),
INVALID_BASE64(BAD_REQUEST, "WEB_006", "잘못된 Base64 문자열입니다"),
UNHANDLED_EXCEPTION(INTERNAL_SERVER_ERROR, ERROR, "WEB_001", "직접적으로 처리되지 않은 예외, 문의해주세요"),
FAILED_VALIDATION(BAD_REQUEST, WARN, "WEB_002", "Request 요청에서 올바르지 않은 값이 있습니다"),
FAILED_PARSING(BAD_REQUEST, WARN, "WEB_003", "Request JSON body를 파싱하지 못했습니다"),
UNSUPPORTED_API(BAD_REQUEST, DEBUG, "WEB_004", "지원하지 않는 API입니다"),
COOKIE_NOT_FOND(BAD_REQUEST, DEBUG, "WEB_005", "요청에 쿠키가 필요합니다"),
INVALID_BASE64(BAD_REQUEST, DEBUG, "WEB_006", "잘못된 Base64 문자열입니다"),

// AuthErrorType
FAILED_AUTHENTICATION(UNAUTHORIZED, "AUTH_001", "인증에 실패하였습니다"),
INVALID_ACCESS_TOKEN(UNAUTHORIZED, "AUTH_002", "유효하지 않은 토큰입니다"),
EXPIRED_ACCESS_TOKEN(UNAUTHORIZED, "AUTH_003", "만료된 토큰입니다"),
MALFORMED_ACCESS_TOKEN(UNAUTHORIZED, "AUTH_004", "잘못된 형식의 토큰입니다"),
TAMPERED_ACCESS_TOKEN(UNAUTHORIZED, "AUTH_005", "변조된 토큰입니다"),
UNSUPPORTED_JWT_TOKEN(UNAUTHORIZED, "AUTH_006", "지원하지 않는 JWT 토큰입니다"),
UNSUPPORTED_SOCIAL_TYPE(UNAUTHORIZED, "AUTH_007", "지원하지 않는 소셜 타입입니다."),
INVALID_CREDENTIALS(UNAUTHORIZED, "AUTH_008", "해당 사용자의 정보가 없거나 일치하지 않아 처리할 수 없습니다."),
FAILED_AUTHENTICATION(UNAUTHORIZED, INFO, "AUTH_001", "인증에 실패하였습니다"),
INVALID_ACCESS_TOKEN(UNAUTHORIZED, DEBUG, "AUTH_002", "유효하지 않은 토큰입니다"),
EXPIRED_ACCESS_TOKEN(UNAUTHORIZED, DEBUG, "AUTH_003", "만료된 토큰입니다"),
MALFORMED_ACCESS_TOKEN(UNAUTHORIZED, DEBUG, "AUTH_004", "잘못된 형식의 토큰입니다"),
TAMPERED_ACCESS_TOKEN(UNAUTHORIZED, DEBUG, "AUTH_005", "변조된 토큰입니다"),
UNSUPPORTED_JWT_TOKEN(UNAUTHORIZED, DEBUG, "AUTH_006", "지원하지 않는 JWT 토큰입니다"),
UNSUPPORTED_SOCIAL_TYPE(UNAUTHORIZED, DEBUG, "AUTH_007", "지원하지 않는 소셜 타입입니다"),
INVALID_CREDENTIALS(UNAUTHORIZED, DEBUG, "AUTH_008", "해당 사용자의 정보가 없거나 일치하지 않아 처리할 수 없습니다"),

// OauthErrorType
USER_NOT_FOUND(NOT_FOUND, "OAUTH_001", "존재하지 않은 사용자 입니다."),
USER_NOT_FOUND(NOT_FOUND, DEBUG, "OAUTH_001", "존재하지 않은 사용자 입니다"),

// DatabaseErrorType
ENTITY_NOT_FOUND(NOT_FOUND, "DB_001", "해당 엔티티를 찾을 수 없습니다"),
VIOLATION_OCCURRED(NOT_ACCEPTABLE, "DB_002", "저장할 수 없는 값입니다"),
ENTITY_NOT_FOUND(NOT_FOUND, DEBUG, "DB_001", "해당 엔티티를 찾을 수 없습니다"),
VIOLATION_OCCURRED(NOT_ACCEPTABLE, ERROR, "DB_002", "저장할 수 없는 값입니다"),

// TimeErrorType
START_AFTER_END(BAD_REQUEST, "TIME_001", "시작 시간이 종료 시간보다 빨라야 합니다"),
START_AFTER_END(BAD_REQUEST, DEBUG, "TIME_001", "시작 시간이 종료 시간보다 빨라야 합니다"),

// RunningErrorType
ROUTE_MUST_HAVE_AT_LEAST_TWO_COORDINATES(BAD_REQUEST, "RUNNING_001", "경로는 최소 2개의 좌표를 가져야 합니다"),
CHALLENGE_MODE_WITH_PERSONAL_GOAL(BAD_REQUEST, "RUNNING_002", "챌린지 모드에서는 개인 목표를 설정할 수 없습니다."),
GOAL_MODE_WITH_CHALLENGE_ID(BAD_REQUEST, "RUNNING_003", "개인 목표 모드에서는 챌린지 ID를 설정할 수 없습니다."),
GOAL_TIME_AND_DISTANCE_BOTH_EXIST(BAD_REQUEST, "RUNNING_004", "개인 목표 시간과 거리 중 하나만 설정해야 합니다."),
ROUTE_MUST_HAVE_AT_LEAST_TWO_COORDINATES(BAD_REQUEST, DEBUG, "RUNNING_001", "경로는 최소 2개의 좌표를 가져야 합니다"),
CHALLENGE_MODE_WITH_PERSONAL_GOAL(BAD_REQUEST, DEBUG, "RUNNING_002", "챌린지 모드에서는 개인 목표를 설정할 수 없습니다"),
GOAL_MODE_WITH_CHALLENGE_ID(BAD_REQUEST, DEBUG, "RUNNING_003", "개인 목표 모드에서는 챌린지 ID를 설정할 수 없습니다"),
GOAL_TIME_AND_DISTANCE_BOTH_EXIST(BAD_REQUEST, DEBUG, "RUNNING_004", "개인 목표 시간과 거리 중 하나만 설정해야 합니다"),

// WeatherErrorType
WEATHER_API_ERROR(SERVICE_UNAVAILABLE, "WEATHER_001", "날씨 API 호출 중 오류가 발생했습니다"),
WEATHER_API_ERROR(SERVICE_UNAVAILABLE, WARN, "WEATHER_001", "날씨 API 호출 중 오류가 발생했습니다"),
;
private final HttpStatus httpStatus;
private final Level level;
private final String code;
private final String message;

public enum Level {
INFO,
DEBUG,
WARN,
ERROR
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@
public class ExceptionRestHandler {
@ExceptionHandler(BaseException.class)
public ResponseEntity<ApiErrorDto> handleBaseException(BaseException e) {
log.warn(e.getMessage());
return toResponseEntity(e.getType(), e.getMessage());
}

@ExceptionHandler(AuthException.class)
public ResponseEntity<ApiErrorDto> handleAuthException(AuthException e) {
log.warn(e.getMessage());
return toResponseEntity(e.getType(), e.getMessage());
}

Expand Down Expand Up @@ -64,6 +62,11 @@ public ResponseEntity<ApiErrorDto> handleInsufficientAuthenticationException(
return toResponseEntity(ErrorType.FAILED_AUTHENTICATION, e.getMessage());
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ApiErrorDto> handleIllegalArgumentException(IllegalArgumentException e) {
return toResponseEntity(ErrorType.FAILED_VALIDATION, e.getMessage());
}

////////////////// 요청 파라미터 예외 / 타입 불일치, Enum 매개변수 관련 예외
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ApiErrorDto> handleMethodArgumentTypeMismatchException(
Expand Down Expand Up @@ -103,7 +106,6 @@ public ResponseEntity<ApiErrorDto> handleMethodArgumentTypeMismatchException(
////////////////// 직렬화 / 역직렬화 예외
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiErrorDto> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
log.warn(ex.getBindingResult().getAllErrors().toString());
return toResponseEntity(
ErrorType.FAILED_VALIDATION,
ex.getBindingResult().getAllErrors().toString());
Expand All @@ -117,21 +119,29 @@ public ResponseEntity<ApiErrorDto> handleHttpMessageNotReadableException(HttpMes
////////////////// Database 관련 예외
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<ApiErrorDto> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
log.warn(ex.getMessage(), ex);
return toResponseEntity(ErrorType.VIOLATION_OCCURRED, ex);
}

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ApiErrorDto> handleConstraintViolationException(ConstraintViolationException ex) {
log.warn(ex.getMessage(), ex);
return toResponseEntity(ErrorType.VIOLATION_OCCURRED, ex);
}

private static ResponseEntity<ApiErrorDto> toResponseEntity(@NotNull ErrorType type, Exception exception) {
return toResponseEntity(type, exception.getMessage());
return toResponseEntity(type, exception.getClass().getName() + ": " + exception.getMessage());
}

private static ResponseEntity<ApiErrorDto> toResponseEntity(@NotNull ErrorType type, String message) {
loggingExceptionByErrorType(type, message);
return ResponseEntity.status(type.httpStatus().value()).body(ApiErrorDto.of(type, message));
}

private static void loggingExceptionByErrorType(ErrorType type, String message) {
switch (type.level()) {
case INFO -> log.info(message);
case DEBUG -> log.debug(message);
case WARN -> log.warn(message);
default -> log.error(message);
}
}
}

0 comments on commit 3aa6cbd

Please sign in to comment.