Skip to content

Commit

Permalink
�v2.2.2
Browse files Browse the repository at this point in the history
* chore: dev/prod 별 센트리 dsn, environment, servername 설정

* chore: logback 전용 Sentry 의존성 추가

* feat: Sentry logback 기능 추가

* feat: Sentry 속성을 주입하는 SentryConfig 추가

* feat: Sentry Exception 테스트용 임시 API 추가

* chore: slack webhook 의존성 주입

* chore: slack 웹훅에 사용될 환경변수 설정

* chore: 에러감지 시 Slack으로 Sentry 주소를 보내주도록 구현

* chore: test용 yml파일에 변경사항 업데이트

* feat: IOException Handler 메서드 추가
  • Loading branch information
hoonyworld authored Nov 14, 2024
2 parents a2abdc3 + adaa6d8 commit 071ff5c
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 29 deletions.
55 changes: 33 additions & 22 deletions main/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,71 +23,82 @@ 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'

// Slack Webhook
implementation 'com.github.maricn:logback-slack-appender:1.4.0'
}

tasks.named('test') {
Expand Down Expand Up @@ -157,4 +168,4 @@ jacocoTestCoverageVerification {
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -108,12 +110,19 @@ public ResponseEntity<ExceptionResponse> handleHttpRequestMethodNotSupportedExce
ErrorStatus.INVALID_INPUT_VALUE.getErrorCode()));
}

@ExceptionHandler(IOException.class)
public ResponseEntity<ExceptionResponse> 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<ExceptionResponse> handleException(Exception e) {
log.error("{}", e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ExceptionResponse.fail(
ErrorStatus.INTERNAL_SERVER_ERROR.getErrorCode()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ private String[] getAuthWhitelist() {
"/meeting/v2/org-user/**",
"/auth/v2",
"/auth/v2/**",
actuatorEndPoint + "/health"
actuatorEndPoint + "/health",
"/sentry" // prod에서 테스트 후 삭제
};
}

Expand Down Expand Up @@ -103,4 +104,4 @@ CorsConfigurationSource corsConfigurationSource() {
return source;
}

}
}
Original file line number Diff line number Diff line change
@@ -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);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> 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");
}
}
}
13 changes: 13 additions & 0 deletions main/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,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: dev
13 changes: 13 additions & 0 deletions main/src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,16 @@ management:
custom:
paths:
eventApply: ${PROD_EVENT_APPLY_PATH}

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
13 changes: 13 additions & 0 deletions main/src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
38 changes: 35 additions & 3 deletions main/src/main/resources/logback-spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,58 @@
<property name="LOG_PATTERN"
value="[%d{yyyy-MM-dd HH:mm:ss}:%-4relative] %green([%thread]) %highlight(%-5level) %boldWhite([%C.%M:%yellow(%L)]) - %msg%n"/>

<appender name="Sentry" class="io.sentry.logback.SentryAppender">
<maxRequestBodySize>always</maxRequestBodySize>
<sendDefaultPii>true</sendDefaultPii>
<tracesSampleRate>1.0</tracesSampleRate>
<minimumEventLevel>ERROR</minimumEventLevel>
<minimumBreadcrumbLevel>DEBUG</minimumBreadcrumbLevel>
</appender>

<springProperty name="SLACK_WEBHOOK_URI" source="logging.slack.webhook-uri"/>
<springProperty name="SENTRY_REPOSITORY_URI" source="logging.sentry.repository-uri"/>
<springProperty name="ENVIRONMENT" source="logging.sentry.environment"/>
<appender name="SLACK" class="com.github.maricn.logback.SlackAppender">
<webhookUri>${SLACK_WEBHOOK_URI}</webhookUri>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>*🚨[${ENVIRONMENT}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level %class - %msg &lt;${SENTRY_REPOSITORY_URI}|Go-To-Sentry&gt;*
%n
</pattern>
</layout>
<username>posting bot</username>
<iconEmoji>:robot_face:</iconEmoji>
<colorCoding>true</colorCoding>
</appender>

<appender name="ASYNC_SLACK" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="SLACK"/>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>

<springProfile name="local">
<include resource="console-appender.xml"/>

<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>

<springProfile name="dev">
<include resource="console-appender.xml"/>

<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="Sentry"/>
<appender-ref ref="ASYNC_SLACK"/>
</root>
</springProfile>

<springProfile name="prod">
<include resource="console-appender.xml"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="Sentry"/>
<appender-ref ref="ASYNC_SLACK"/>
</root>
</springProfile>

Expand All @@ -32,4 +64,4 @@
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>
</configuration>

0 comments on commit 071ff5c

Please sign in to comment.