From c50c00330b7394e6fbc9feb4de9ae4017e1afa53 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Wed, 13 Nov 2024 20:12:19 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20dev/prod=20=EB=B3=84=20=EC=84=BC?= =?UTF-8?q?=ED=8A=B8=EB=A6=AC=20dsn,=20environment,=20servername=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main/resources/application-dev.yml | 5 +++++ main/src/main/resources/application-prod.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/main/src/main/resources/application-dev.yml b/main/src/main/resources/application-dev.yml index 9c73fe89..9eed990b 100644 --- a/main/src/main/resources/application-dev.yml +++ b/main/src/main/resources/application-dev.yml @@ -99,3 +99,8 @@ management: custom: paths: eventApply: ${DEV_EVENT_APPLY_PATH} + +sentry: + dsn: ${SENTRY_DSN} + environment: ${DEV_SENTRY_ENVIRONMENT} + servername: ${DEV_SENTRY_SERVERNAME} diff --git a/main/src/main/resources/application-prod.yml b/main/src/main/resources/application-prod.yml index bba3a8ea..be80f81f 100644 --- a/main/src/main/resources/application-prod.yml +++ b/main/src/main/resources/application-prod.yml @@ -99,3 +99,8 @@ management: custom: paths: eventApply: ${PROD_EVENT_APPLY_PATH} + +sentry: + dsn: ${SENTRY_DSN} + environment: ${PROD_SENTRY_ENVIRONMENT} + servername: ${PROD_SENTRY_SERVERNAME} From 6a0a36911819579b866f8dbfde00cbf16deac5f6 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Wed, 13 Nov 2024 20:13:15 +0900 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20logback=20=EC=A0=84=EC=9A=A9=20S?= =?UTF-8?q?entry=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/build.gradle | 52 +++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/main/build.gradle b/main/build.gradle index c64f1fa7..3835fda9 100644 --- a/main/build.gradle +++ b/main/build.gradle @@ -23,71 +23,79 @@ repositories { } dependencies { + // Spring Boot Dependencies implementation 'org.springframework.boot:spring-boot-starter-web' - // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' implementation 'org.springframework.boot:spring-boot-starter-webflux:3.1.5' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' - // lombok + // Lombok Dependencies (Compile-time code generation library) compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' + // Development Tools developmentOnly 'org.springframework.boot:spring-boot-devtools' + // Test Dependencies testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.testcontainers:testcontainers:1.17.3' + testImplementation 'org.testcontainers:junit-jupiter:1.16.2' + testImplementation 'org.testcontainers:postgresql:1.17.3' + testImplementation 'org.testcontainers:jdbc' + + // Apache Commons Dependencies + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.14.0' + + // AOP (Aspect-Oriented Programming) for cross-cutting concerns + implementation 'org.springframework.boot:spring-boot-starter-aop' + + // Database and Persistence Dependencies implementation group: 'org.postgresql', name: 'postgresql', version: '42.6.0' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.postgresql:postgresql:42.3.0' - // jsonb 타입 핸들링 위함 + // jsonb Type Handling implementation 'io.hypersistence:hypersistence-utils-hibernate-62:3.6.0' + // JWT Dependencies for Security and Authentication implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' implementation 'com.auth0:java-jwt:4.4.0' - // h2 + // H2 Database (for testing and in-memory DB) runtimeOnly 'com.h2database:h2' - // mac m1 setting + // macOS M1 Support (Network Resolver for macOS) implementation 'io.netty:netty-resolver-dns-native-macos:4.1.68.Final:osx-aarch_64' + // Spring Cloud OpenFeign (Service-to-service communication) implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.0.3' - // test container - testImplementation 'org.testcontainers:testcontainers:1.17.3' // TC 의존성 - testImplementation 'org.testcontainers:junit-jupiter:1.16.2' // TC 의존성 - testImplementation 'org.testcontainers:postgresql:1.17.3' // PostgreSQL 컨테이너 사용 - testImplementation 'org.testcontainers:jdbc' // DB와의 JDBC connection - implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.14.0' - - // aop - implementation 'org.springframework.boot:spring-boot-starter-aop' - - // MapStruct + // MapStruct (DTO transformation code generation) implementation 'org.mapstruct:mapstruct:1.5.3.Final' annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final' - // queryDsl + // QueryDSL (JPA Query Generation) implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" - // AWS SDK for S3 + // AWS SDK for S3 (for file upload and download) implementation "software.amazon.awssdk:s3:2.27.0" - // csv 관련 + // CSV Processing Library implementation 'com.opencsv:opencsv:5.5.2' - // prometheus + // Prometheus (Monitoring and Metrics Collection) implementation 'io.micrometer:micrometer-registry-prometheus' + + // Sentry Logback (Error Tracking) + implementation 'io.sentry:sentry-logback:7.17.0' } tasks.named('test') { @@ -157,4 +165,4 @@ jacocoTestCoverageVerification { ] } } -} \ No newline at end of file +} From d99d25fac3838490ae9d426dce0faf71c98deb72 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Wed, 13 Nov 2024 20:16:40 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20Sentry=20logback=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main/resources/logback-spring.xml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/main/src/main/resources/logback-spring.xml b/main/src/main/resources/logback-spring.xml index 3c008a2b..5c9c80fd 100644 --- a/main/src/main/resources/logback-spring.xml +++ b/main/src/main/resources/logback-spring.xml @@ -3,9 +3,16 @@ + + always + true + 1.0 + ERROR + DEBUG + + - @@ -13,9 +20,9 @@ - + @@ -23,6 +30,7 @@ + @@ -32,4 +40,4 @@ - \ No newline at end of file + From a7e03edd81b911e77871c0480fdd2103e601221c Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Wed, 13 Nov 2024 20:19:08 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20Sentry=20=EC=86=8D=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=A3=BC=EC=9E=85=ED=95=98=EB=8A=94=20SentryConfig?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/main/global/config/SentryConfig.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 main/src/main/java/org/sopt/makers/crew/main/global/config/SentryConfig.java diff --git a/main/src/main/java/org/sopt/makers/crew/main/global/config/SentryConfig.java b/main/src/main/java/org/sopt/makers/crew/main/global/config/SentryConfig.java new file mode 100644 index 00000000..e18d9647 --- /dev/null +++ b/main/src/main/java/org/sopt/makers/crew/main/global/config/SentryConfig.java @@ -0,0 +1,29 @@ +package org.sopt.makers.crew.main.global.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import io.sentry.Sentry; +import jakarta.annotation.PostConstruct; + +@Configuration +public class SentryConfig { + + @Value("${sentry.dsn}") + private String sentryDsn; + + @Value("${sentry.environment}") + private String environment; + + @Value("${sentry.servername}") + private String serverName; + + @PostConstruct + public void initSentry() { + Sentry.init(options -> { + options.setDsn(sentryDsn); + options.setEnvironment(environment); + options.setServerName(serverName); + }); + } +} From 2484388283af446905a3798c99731545049fbdff Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Wed, 13 Nov 2024 20:20:12 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20Sentry=20Exception=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=9A=A9=20=EC=9E=84=EC=8B=9C=20API=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/global/config/SecurityConfig.java | 5 ++-- .../main/global/sentry/SentryController.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 main/src/main/java/org/sopt/makers/crew/main/global/sentry/SentryController.java diff --git a/main/src/main/java/org/sopt/makers/crew/main/global/config/SecurityConfig.java b/main/src/main/java/org/sopt/makers/crew/main/global/config/SecurityConfig.java index f810a2af..5cff0a6e 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/global/config/SecurityConfig.java +++ b/main/src/main/java/org/sopt/makers/crew/main/global/config/SecurityConfig.java @@ -52,7 +52,8 @@ private String[] getAuthWhitelist() { "/meeting/v2/org-user/**", "/auth/v2", "/auth/v2/**", - actuatorEndPoint + "/health" + actuatorEndPoint + "/health", + "/sentry" // prod에서 테스트 후 삭제 }; } @@ -103,4 +104,4 @@ CorsConfigurationSource corsConfigurationSource() { return source; } -} \ No newline at end of file +} diff --git a/main/src/main/java/org/sopt/makers/crew/main/global/sentry/SentryController.java b/main/src/main/java/org/sopt/makers/crew/main/global/sentry/SentryController.java new file mode 100644 index 00000000..d16b2235 --- /dev/null +++ b/main/src/main/java/org/sopt/makers/crew/main/global/sentry/SentryController.java @@ -0,0 +1,26 @@ +package org.sopt.makers.crew.main.global.sentry; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.sentry.Sentry; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@RequestMapping("/sentry") +public class SentryController { + + @GetMapping + public ResponseEntity testSentry() { // prod에서 테스트 후 삭제 + try { + throw new Exception("This is a test exception for Sentry."); + } catch (Exception e) { + Sentry.captureException(e); + log.error("Exception captured in Sentry", e); + return ResponseEntity.status(500).body("Exception captured in Sentry"); + } + } +} From 5b806823a8b559e7addba35a86bce9cf3042a3d4 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Thu, 14 Nov 2024 19:01:57 +0900 Subject: [PATCH 06/10] =?UTF-8?q?chore:=20slack=20webhook=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/build.gradle b/main/build.gradle index 3835fda9..1faa3948 100644 --- a/main/build.gradle +++ b/main/build.gradle @@ -96,6 +96,9 @@ dependencies { // Sentry Logback (Error Tracking) implementation 'io.sentry:sentry-logback:7.17.0' + + // Slack Webhook + implementation 'com.github.maricn:logback-slack-appender:1.4.0' } tasks.named('test') { From 0d0e5c192ad2db50da7a4f4f2f0bbef81dd3a409 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Thu, 14 Nov 2024 19:03:49 +0900 Subject: [PATCH 07/10] =?UTF-8?q?chore:=20slack=20=EC=9B=B9=ED=9B=85?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=A0=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main/resources/application-dev.yml | 8 ++++++++ main/src/main/resources/application-prod.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/main/src/main/resources/application-dev.yml b/main/src/main/resources/application-dev.yml index 9eed990b..9f73f98c 100644 --- a/main/src/main/resources/application-dev.yml +++ b/main/src/main/resources/application-dev.yml @@ -104,3 +104,11 @@ sentry: dsn: ${SENTRY_DSN} environment: ${DEV_SENTRY_ENVIRONMENT} servername: ${DEV_SENTRY_SERVERNAME} + +logging: + slack: + webhook-uri: ${SENTRY_SLACK_WEBHOOK_URI} + config: classpath:logback-spring.xml + sentry: + repository-uri: ${SENTRY_REPOSITORY_URI} + environment: dev diff --git a/main/src/main/resources/application-prod.yml b/main/src/main/resources/application-prod.yml index be80f81f..eaabdca2 100644 --- a/main/src/main/resources/application-prod.yml +++ b/main/src/main/resources/application-prod.yml @@ -104,3 +104,11 @@ sentry: dsn: ${SENTRY_DSN} environment: ${PROD_SENTRY_ENVIRONMENT} servername: ${PROD_SENTRY_SERVERNAME} + +logging: + slack: + webhook-uri: ${SENTRY_SLACK_WEBHOOK_URI} + config: classpath:logback-spring.xml + sentry: + repository-uri: ${SENTRY_REPOSITORY_URI} + environment: prod From 4292d9600917fa9ac71d316d2e5cfec1a7bab1c0 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Thu, 14 Nov 2024 19:04:33 +0900 Subject: [PATCH 08/10] =?UTF-8?q?chore:=20=EC=97=90=EB=9F=AC=EA=B0=90?= =?UTF-8?q?=EC=A7=80=20=EC=8B=9C=20Slack=EC=9C=BC=EB=A1=9C=20Sentry=20?= =?UTF-8?q?=EC=A3=BC=EC=86=8C=EB=A5=BC=20=EB=B3=B4=EB=82=B4=EC=A3=BC?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main/resources/logback-spring.xml | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/main/src/main/resources/logback-spring.xml b/main/src/main/resources/logback-spring.xml index 5c9c80fd..a96141ca 100644 --- a/main/src/main/resources/logback-spring.xml +++ b/main/src/main/resources/logback-spring.xml @@ -11,6 +11,28 @@ DEBUG + + + + + ${SLACK_WEBHOOK_URI} + + *🚨[${ENVIRONMENT}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level %class - %msg <${SENTRY_REPOSITORY_URI}|Go-To-Sentry>* + %n + + + posting bot + :robot_face: + true + + + + + + ERROR + + + @@ -23,6 +45,7 @@ + @@ -31,6 +54,7 @@ + From b6f4689b8aaa9a478d2f8878757c868645e3d364 Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Thu, 14 Nov 2024 19:44:36 +0900 Subject: [PATCH 09/10] =?UTF-8?q?chore:=20test=EC=9A=A9=20yml=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=97=90=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main/resources/application-test.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/main/src/main/resources/application-test.yml b/main/src/main/resources/application-test.yml index a7e232fc..37ea31a7 100644 --- a/main/src/main/resources/application-test.yml +++ b/main/src/main/resources/application-test.yml @@ -98,3 +98,16 @@ management: custom: paths: eventApply: ${DEV_EVENT_APPLY_PATH} + +sentry: + dsn: ${SENTRY_DSN} + environment: ${DEV_SENTRY_ENVIRONMENT} + servername: ${DEV_SENTRY_SERVERNAME} + +logging: + slack: + webhook-uri: ${SENTRY_SLACK_WEBHOOK_URI} + config: classpath:logback-spring.xml + sentry: + repository-uri: ${SENTRY_REPOSITORY_URI} + environment: test From 75a92c52d92f1307128cf76beebe73eb6035372c Mon Sep 17 00:00:00 2001 From: DongHoon Lee Date: Thu, 14 Nov 2024 20:43:48 +0900 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20IOException=20Handler=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/advice/ControllerExceptionAdvice.java | 13 +++++++++++-- .../crew/main/global/exception/ErrorStatus.java | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/main/src/main/java/org/sopt/makers/crew/main/global/advice/ControllerExceptionAdvice.java b/main/src/main/java/org/sopt/makers/crew/main/global/advice/ControllerExceptionAdvice.java index 5b361319..77bed3c7 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/global/advice/ControllerExceptionAdvice.java +++ b/main/src/main/java/org/sopt/makers/crew/main/global/advice/ControllerExceptionAdvice.java @@ -1,8 +1,10 @@ package org.sopt.makers.crew.main.global.advice; +import java.io.IOException; + import org.sopt.makers.crew.main.global.exception.BaseException; -import org.sopt.makers.crew.main.global.exception.ExceptionResponse; import org.sopt.makers.crew.main.global.exception.ErrorStatus; +import org.sopt.makers.crew.main.global.exception.ExceptionResponse; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -108,6 +110,14 @@ public ResponseEntity handleHttpRequestMethodNotSupportedExce ErrorStatus.INVALID_INPUT_VALUE.getErrorCode())); } + @ExceptionHandler(IOException.class) + public ResponseEntity handleIOException(IOException e) { + log.warn("{}", e.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ExceptionResponse.fail( + ErrorStatus.IO_EXCEPTION.getErrorCode())); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception e) { log.error("{}", e.getMessage()); @@ -115,5 +125,4 @@ public ResponseEntity handleException(Exception e) { .body(ExceptionResponse.fail( ErrorStatus.INTERNAL_SERVER_ERROR.getErrorCode())); } - } diff --git a/main/src/main/java/org/sopt/makers/crew/main/global/exception/ErrorStatus.java b/main/src/main/java/org/sopt/makers/crew/main/global/exception/ErrorStatus.java index bb4470f8..90e5e61d 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/global/exception/ErrorStatus.java +++ b/main/src/main/java/org/sopt/makers/crew/main/global/exception/ErrorStatus.java @@ -38,6 +38,7 @@ public enum ErrorStatus { CO_LEADER_CANNOT_APPLY("공동 모임장은 신청할 수 없습니다."), LEADER_CANNOT_BE_CO_LEADER_APPLY("모임장은 공동 모임장이 될 수 없습니다."), NOT_ALLOW_MEETING_APPLY("허용되지 않는 모임 신청입니다."), + IO_EXCEPTION("파일 입출력 오류가 발생했습니다."), /** * 401 UNAUTHORIZED