From 81376a909cba6c5b7d6338c183fa9b1e1c724094 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Fri, 28 Feb 2025 15:54:51 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EB=94=94=EC=8A=A4=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=97=90=EB=9F=AC=20=EC=95=8C=EB=A6=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/HttpInterfaceConfig.java | 6 ++ .../ApplicationControllerAdvice.java | 13 +++- .../common/exception/DiscordClient.java | 27 +++++++ .../common/exception/DiscordMessage.java | 18 +++++ .../exception/DiscordMessageSender.java | 78 +++++++++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/swyp8team2/common/exception/DiscordClient.java create mode 100644 src/main/java/com/swyp8team2/common/exception/DiscordMessage.java create mode 100644 src/main/java/com/swyp8team2/common/exception/DiscordMessageSender.java diff --git a/src/main/java/com/swyp8team2/common/config/HttpInterfaceConfig.java b/src/main/java/com/swyp8team2/common/config/HttpInterfaceConfig.java index b95414e9..6f385379 100644 --- a/src/main/java/com/swyp8team2/common/config/HttpInterfaceConfig.java +++ b/src/main/java/com/swyp8team2/common/config/HttpInterfaceConfig.java @@ -1,6 +1,7 @@ package com.swyp8team2.common.config; import com.swyp8team2.auth.application.oauth.KakaoOAuthClient; +import com.swyp8team2.common.exception.DiscordClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestClient; @@ -17,4 +18,9 @@ public KakaoOAuthClient kakaoAuthClient() { .builderFor(adapter).build(); return build.createClient(KakaoOAuthClient.class); } + + @Bean + public RestClient restClient() { + return RestClient.create(); + } } diff --git a/src/main/java/com/swyp8team2/common/exception/ApplicationControllerAdvice.java b/src/main/java/com/swyp8team2/common/exception/ApplicationControllerAdvice.java index 3d2fc530..4dc5fd55 100644 --- a/src/main/java/com/swyp8team2/common/exception/ApplicationControllerAdvice.java +++ b/src/main/java/com/swyp8team2/common/exception/ApplicationControllerAdvice.java @@ -1,6 +1,8 @@ package com.swyp8team2.common.exception; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; @@ -9,17 +11,23 @@ import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.annotation.HandlerMethodValidationException; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.resource.NoResourceFoundException; import javax.naming.AuthenticationException; import java.nio.file.AccessDeniedException; +import java.util.Arrays; @Slf4j @RestControllerAdvice +@RequiredArgsConstructor public class ApplicationControllerAdvice { + private final DiscordMessageSender discordMessageSender; + private final Environment environment; + @ExceptionHandler(BadRequestException.class) public ResponseEntity handle(BadRequestException e) { ErrorResponse response = new ErrorResponse(e.getErrorCode()); @@ -72,8 +80,11 @@ public ResponseEntity handle(AccessDeniedException e) { } @ExceptionHandler(Exception.class) - public ResponseEntity handle(Exception e) { + public ResponseEntity handle(Exception e, WebRequest webRequest) { log.error("Exception", e); + if (!Arrays.asList(environment.getActiveProfiles()).contains("local")) { + discordMessageSender.sendDiscordAlarm(e, webRequest); + } return ResponseEntity.internalServerError() .body(new ErrorResponse(ErrorCode.INTERNAL_SERVER_ERROR)); } diff --git a/src/main/java/com/swyp8team2/common/exception/DiscordClient.java b/src/main/java/com/swyp8team2/common/exception/DiscordClient.java new file mode 100644 index 00000000..53de6ae4 --- /dev/null +++ b/src/main/java/com/swyp8team2/common/exception/DiscordClient.java @@ -0,0 +1,27 @@ +package com.swyp8team2.common.exception; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClient; + +@Component +public class DiscordClient { + + private final RestClient restClient; + private final String discordWebhookUrl; + + public DiscordClient( + RestClient restClient, + @Value("${discord.webhook.url}") String discordWebhookUrl) { + this.restClient = restClient; + this.discordWebhookUrl = discordWebhookUrl; + } + + public void sendAlarm(DiscordMessage request) { + restClient.post() + .uri(discordWebhookUrl) + .body(request) + .retrieve() + .toBodilessEntity(); + } +} diff --git a/src/main/java/com/swyp8team2/common/exception/DiscordMessage.java b/src/main/java/com/swyp8team2/common/exception/DiscordMessage.java new file mode 100644 index 00000000..9f966081 --- /dev/null +++ b/src/main/java/com/swyp8team2/common/exception/DiscordMessage.java @@ -0,0 +1,18 @@ +package com.swyp8team2.common.exception; + +import lombok.Builder; + +import java.util.List; + +@Builder +public record DiscordMessage( + String content, + List embeds +) { + + @Builder + record Embed( + String title, + String description + ) { } +} diff --git a/src/main/java/com/swyp8team2/common/exception/DiscordMessageSender.java b/src/main/java/com/swyp8team2/common/exception/DiscordMessageSender.java new file mode 100644 index 00000000..122e0d53 --- /dev/null +++ b/src/main/java/com/swyp8team2/common/exception/DiscordMessageSender.java @@ -0,0 +1,78 @@ +package com.swyp8team2.common.exception; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.context.request.WebRequest; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.time.Clock; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class DiscordMessageSender { + + private final DiscordClient discordClient; + private final Clock clock; + private final Environment environment; + + public void sendDiscordAlarm(Exception e, WebRequest request) { + discordClient.sendAlarm(createMessage(e, request)); + } + + private DiscordMessage createMessage(Exception e, WebRequest request) { + List profiles = Arrays.asList(environment.getActiveProfiles()); + return DiscordMessage.builder() + .content("# 🚨 뗐ëŸŦ ë°œėƒ") + .embeds( + List.of( + DiscordMessage.Embed.builder() + .title("â„šī¸ 뗐ëŸŦ ė •ëŗ´") + .description( + """ + ### 📝 환ę˛Ŋ ė •ëŗ´ + %s + ### 🕖 ë°œėƒ ė‹œę°„ + %s + ### 🔗 ėš”ė˛­ URL + %s + ### 📄 Stack Trace + ``` + %s + ``` + """.formatted( + String.join("", profiles), + Instant.now(clock), + createRequestFullPath(request), + getStackTrace(e).substring(0, 1000) + )) + .build() + ) + ) + .build(); + } + + private String createRequestFullPath(WebRequest webRequest) { + HttpServletRequest request = ((ServletWebRequest) webRequest).getRequest(); + String fullPath = request.getMethod() + " " + request.getRequestURL(); + + String queryString = request.getQueryString(); + if (queryString != null) { + fullPath += "?" + queryString; + } + + return fullPath; + } + + private String getStackTrace(Exception e) { + StringWriter stringWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } +} From c4c049986d0cbfa1b5ec46f8e00b99dbca7ff760 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Fri, 28 Feb 2025 16:22:27 +0900 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20=EC=84=A4=EC=A0=95=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-config b/server-config index 72816997..68ef107f 160000 --- a/server-config +++ b/server-config @@ -1 +1 @@ -Subproject commit 72816997e97767c17a566b55a569c6faad7c5f25 +Subproject commit 68ef107fc0155483439e02560e94159e61241b0b