diff --git a/src/main/java/org/runnect/server/common/advice/ControllerExceptionAdvice.java b/src/main/java/org/runnect/server/common/advice/ControllerExceptionAdvice.java index 6642621..71cbc50 100644 --- a/src/main/java/org/runnect/server/common/advice/ControllerExceptionAdvice.java +++ b/src/main/java/org/runnect/server/common/advice/ControllerExceptionAdvice.java @@ -1,7 +1,6 @@ package org.runnect.server.common.advice; import io.sentry.Sentry; -import java.io.IOException; import java.util.Objects; import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolationException; @@ -10,6 +9,7 @@ import org.runnect.server.common.dto.ApiResponseDto; import org.runnect.server.common.exception.BasicException; import org.runnect.server.config.slack.SlackApi; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +@Slf4j @RestControllerAdvice @Component @RequiredArgsConstructor @@ -71,9 +72,17 @@ protected ApiResponseDto handleMissingRequestParameterException(final MissingSer */ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) - protected ApiResponseDto handleException(final Exception error, final HttpServletRequest request) throws IOException { - slackApi.sendAlert(error, request); - Sentry.captureException(error); + protected ApiResponseDto handleException(final Exception error, final HttpServletRequest request) { + try { + slackApi.sendAlert(error, request); + } catch (Exception e) { + log.error("Slack 알림 전송 실패", e); + } + try { + Sentry.captureException(error); + } catch (Exception e) { + log.error("Sentry 전송 실패", e); + } return ApiResponseDto.error(ErrorStatus.INTERNAL_SERVER_ERROR); } diff --git a/src/main/java/org/runnect/server/config/slack/SlackApi.java b/src/main/java/org/runnect/server/config/slack/SlackApi.java index d6fe854..19df6f5 100644 --- a/src/main/java/org/runnect/server/config/slack/SlackApi.java +++ b/src/main/java/org/runnect/server/config/slack/SlackApi.java @@ -27,8 +27,6 @@ public class SlackApi { private final static String NEW_LINE = "\n"; private final static String DOUBLE_NEW_LINE = "\n\n"; - private StringBuilder sb = new StringBuilder(); - public void sendAlert(Exception error, HttpServletRequest request) throws IOException { List layoutBlocks = generateLayoutBlock(error, request); @@ -53,7 +51,7 @@ private List generateLayoutBlock(Exception error, HttpServletReques } private String generateErrorMessage(Exception error) { - sb.setLength(0); + StringBuilder sb = new StringBuilder(); sb.append("*[🔥 Exception]*" + NEW_LINE + error.toString() + DOUBLE_NEW_LINE); sb.append("*[📩 From]*" + NEW_LINE + readRootStackTrace(error) + DOUBLE_NEW_LINE); @@ -61,7 +59,7 @@ private String generateErrorMessage(Exception error) { } private String generateErrorPointMessage(HttpServletRequest request) { - sb.setLength(0); + StringBuilder sb = new StringBuilder(); sb.append("*[🧾세부정보]*" + NEW_LINE); sb.append("Request URL : " + request.getRequestURL().toString() + NEW_LINE); sb.append("Request Method : " + request.getMethod() + NEW_LINE); @@ -71,6 +69,9 @@ private String generateErrorPointMessage(HttpServletRequest request) { } private String readRootStackTrace(Exception error) { + if (error.getStackTrace() == null || error.getStackTrace().length == 0) { + return "Unknown"; + } return error.getStackTrace()[0].toString(); } diff --git a/src/main/java/org/runnect/server/record/service/RecordService.java b/src/main/java/org/runnect/server/record/service/RecordService.java index d8e1370..c2dc96b 100644 --- a/src/main/java/org/runnect/server/record/service/RecordService.java +++ b/src/main/java/org/runnect/server/record/service/RecordService.java @@ -110,10 +110,15 @@ public GetRecordResponseDto getRecordByUser(Long userId) { DepartureResponse departure = DepartureResponse.of(course.getDepartureRegion(), course.getDepartureCity()); - // 건강 데이터 조회 - HealthDataResponse healthData = recordHealthDataRepository.findByRecordId(record.getId()) - .map(h -> HealthDataResponse.of(h.getAvgHeartRate(), h.getCalories())) - .orElse(null); + // 건강 데이터 조회 (실패해도 기록 목록은 정상 반환) + HealthDataResponse healthData = null; + try { + healthData = recordHealthDataRepository.findByRecordId(record.getId()) + .map(h -> HealthDataResponse.of(h.getAvgHeartRate(), h.getCalories())) + .orElse(null); + } catch (Exception e) { + // 건강 데이터 테이블 미생성 등 예외 발생 시 무시 + } RecordResponse recordResponse = RecordResponse.of(record.getId(), course.getId(), publicCourseId, userId, record.getTitle(), course.getImage(), record.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")), course.getDistance(), record.getTime().toString(),