package com.kamco.cd.kamcoback.config; import com.kamco.cd.kamcoback.config.api.ApiLogFunction; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.log.dto.ErrorLogDto; import com.kamco.cd.kamcoback.postgres.entity.ErrorLogEntity; import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository; import jakarta.persistence.EntityNotFoundException; import jakarta.servlet.http.HttpServletRequest; import java.nio.file.AccessDeniedException; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.NoSuchElementException; import java.util.Optional; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.client.HttpServerErrorException; @Slf4j @Order(value = 1) @RestControllerAdvice public class GlobalExceptionHandler { private final ErrorLogRepository errorLogRepository; public GlobalExceptionHandler(ErrorLogRepository errorLogRepository) { this.errorLogRepository = errorLogRepository; } @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) @ExceptionHandler(EntityNotFoundException.class) public ApiResponseDto handlerEntityNotFoundException( EntityNotFoundException e, HttpServletRequest request) { log.warn("[EntityNotFoundException] resource :{} ", e.getMessage()); String codeName = "NOT_FOUND_DATA"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf("UNPROCESSABLE_ENTITY"), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf("UNPROCESSABLE_ENTITY"), errorLog.getId()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(HttpMessageNotReadableException.class) public ApiResponseDto handleUnreadable( HttpMessageNotReadableException e, HttpServletRequest request) { log.warn("[HttpMessageNotReadableException] resource :{} ", e.getMessage()); String codeName = "BAD_REQUEST"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(NoSuchElementException.class) public ApiResponseDto handlerNoSuchElementException( NoSuchElementException e, HttpServletRequest request) { log.warn("[NoSuchElementException] resource :{} ", e.getMessage()); String codeName = "NOT_FOUND_DATA"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf("NOT_FOUND"), errorLog.getId()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(IllegalArgumentException.class) public ApiResponseDto handlerIllegalArgumentException( IllegalArgumentException e, HttpServletRequest request) { log.warn("[handlerIllegalArgumentException] resource :{} ", e.getMessage()); String codeName = "BAD_REQUEST"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) @ExceptionHandler(DataIntegrityViolationException.class) public ApiResponseDto handlerDataIntegrityViolationException( DataIntegrityViolationException e, HttpServletRequest request) { log.warn("[DataIntegrityViolationException] resource :{} ", e.getMessage()); String codeName = "DATA_INTEGRITY_ERROR"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf("UNPROCESSABLE_ENTITY"), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf("UNPROCESSABLE_ENTITY"), errorLog.getId()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ApiResponseDto handlerMethodArgumentNotValidException( MethodArgumentNotValidException e, HttpServletRequest request) { log.warn("[MethodArgumentNotValidException] resource :{} ", e.getMessage()); String codeName = "BAD_REQUEST"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.UNAUTHORIZED) @ExceptionHandler(AccessDeniedException.class) public ApiResponseDto handlerAccessDeniedException( AccessDeniedException e, HttpServletRequest request) { log.warn("[AccessDeniedException] resource :{} ", e.getMessage()); String codeName = "UNAUTHORIZED"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.ERROR, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.BAD_GATEWAY) @ExceptionHandler(HttpServerErrorException.BadGateway.class) public ApiResponseDto handlerHttpServerErrorException( HttpServerErrorException e, HttpServletRequest request) { log.warn("[HttpServerErrorException] resource :{} ", e.getMessage()); String codeName = "BAD_GATEWAY"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) @ExceptionHandler(IllegalStateException.class) public ApiResponseDto handlerIllegalStateException( IllegalStateException e, HttpServletRequest request) { log.warn("[IllegalStateException] resource :{} ", e.getMessage()); String codeName = "UNPROCESSABLE_ENTITY"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(RuntimeException.class) public ApiResponseDto handlerRuntimeException( RuntimeException e, HttpServletRequest request) { log.warn("[RuntimeException] resource :{} ", e.getMessage()); String codeName = "INTERNAL_SERVER_ERROR"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) public ApiResponseDto handlerException(Exception e, HttpServletRequest request) { log.warn("[Exception] resource :{} ", e.getMessage()); String codeName = "INTERNAL_SERVER_ERROR"; ErrorLogEntity errorLog = saveErrerLogData( request, ApiResponseCode.getCode(codeName), HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace()); return ApiResponseDto.createException( ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId()); } /** * 에러 로그 테이블 저장 로직 * * @param request : request * @param errorCode : 정의된 enum errorCode * @param httpStatus : HttpStatus 값 * @param logErrorLevel : WARNING, ERROR, CRITICAL * @param stackTrace : 에러 내용 * @return : insert하고 결과로 받은 Entity */ private ErrorLogEntity saveErrerLogData( HttpServletRequest request, ApiResponseCode errorCode, HttpStatus httpStatus, ErrorLogDto.LogErrorLevel logErrorLevel, StackTraceElement[] stackTrace) { // TODO : 로그인 개발되면 이것도 연결해야 함 Long userid = Long.valueOf(Optional.ofNullable(ApiLogFunction.getUserId(request)).orElse("1")); // TODO : stackTrace limit 20줄? 확인 필요 String stackTraceStr = Arrays.stream(stackTrace) // .limit(20) .map(StackTraceElement::toString) .collect(Collectors.joining("\n")) .substring(0, Math.min(stackTrace.length, 255)); ; ErrorLogEntity errorLogEntity = new ErrorLogEntity( request.getRequestURI(), ApiLogFunction.getEventType(request), logErrorLevel, String.valueOf(httpStatus.value()), errorCode.getText(), stackTraceStr, userid, ZonedDateTime.now()); return errorLogRepository.save(errorLogEntity); } }