Skip to content

Commit

Permalink
deploy-be: cruru version 1.1.2 운영 서버 배포 (v24.10.14) (#812)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: HyungHoKim00 <[email protected]>
Co-authored-by: Do Yeop Kim <[email protected]>
Co-authored-by: Kwoun Ki Ho <[email protected]>
  • Loading branch information
5 people authored Oct 15, 2024
1 parent 6f6c7e3 commit f95f65b
Show file tree
Hide file tree
Showing 53 changed files with 794 additions and 468 deletions.
1 change: 1 addition & 0 deletions .github/workflows/be-cd_dev-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
MONITORING_BINDING_PORT=${{ secrets.MONITORING_BINDING_PORT }}
MONITORING_PORT=${{ secrets.MONITORING_PORT }}
MONITORING_BASE_PATH=${{ secrets.MONITORING_BASE_PATH }}
MONITORING_PROFILE=${{ secrets.MONITORING_PROFILE }}
# Apply-form post URL generating format
APPLY_POST_BASE_URL=${{ secrets.APPLY_POST_BASE_URL }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/be-cd_prod-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ jobs:
MONITORING_BINDING_PORT=${{ secrets.MONITORING_BINDING_PORT }}
MONITORING_PORT=${{ secrets.MONITORING_PORT }}
MONITORING_BASE_PATH=${{ secrets.MONITORING_BASE_PATH }}
MONITORING_PROFILE=${{ secrets.MONITORING_PROFILE }}
# Apply configuration server info from Github secrets
APPLY_POST_BASE_URL=${{ secrets.APPLY_POST_BASE_URL }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/be-cd_test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ jobs:
MONITORING_BINDING_PORT=${{ secrets.MONITORING_BINDING_PORT }}
MONITORING_PORT=${{ secrets.MONITORING_PORT }}
MONITORING_BASE_PATH=${{ secrets.MONITORING_BASE_PATH }}
MONITORING_PROFILE=${{ secrets.MONITORING_PROFILE }}
# Apply configuration server info from Github secrets
APPLY_POST_BASE_URL=${{ secrets.APPLY_POST_BASE_URL }}
Expand Down
1 change: 1 addition & 0 deletions backend/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ services:
environment:
TZ: Asia/Seoul
MONITORING_INSTANCE_ADDR_LOKI_PORT: ${MONITORING_INSTANCE_ADDR_LOKI_PORT}
MONITORING_PROFILE: ${MONITORING_PROFILE}
container_name: promtail
image: grafana/promtail:latest
volumes:
Expand Down
1 change: 1 addition & 0 deletions backend/docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
environment:
TZ: Asia/Seoul
MONITORING_INSTANCE_ADDR_LOKI_PORT: ${MONITORING_INSTANCE_ADDR_LOKI_PORT}
MONITORING_PROFILE: ${MONITORING_PROFILE}
container_name: promtail
image: grafana/promtail:latest
volumes:
Expand Down
1 change: 1 addition & 0 deletions backend/docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
environment:
TZ: Asia/Seoul
MONITORING_INSTANCE_ADDR_LOKI_PORT: ${MONITORING_INSTANCE_ADDR_LOKI_PORT}
MONITORING_PROFILE: ${MONITORING_PROFILE}
container_name: promtail
image: grafana/promtail:latest
volumes:
Expand Down
63 changes: 12 additions & 51 deletions backend/promtail-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,74 +14,55 @@ scrape_configs:
- targets:
- localhost
labels:
job: error_logs
job: ${MONITORING_PROFILE}_error_logs
__path__: /log/error/*.log
pipeline_stages:
- json:
expressions:
timestamp: timestamp
level: level
logger: logger
httpMethod: httpMethod
requestId: requestId
requestUri: requestUri
requestMethod: requestMethod
statusCode: statusCode
sourceClass: sourceClass
sourceMethod: sourceMethod
exceptionClass: exceptionClass
exceptionMessage: exceptionMessage
module: module
msg: message
environment: environment
- labels:
level:
logger:
httpMethod:
requestUri:
statusCode:
sourceClass:
sourceMethod:
exceptionClass:
exceptionMessage:
module:
environment:
- timestamp:
source: timestamp
format: 2006-01-02T15:04:05.000
location: "Asia/Seoul"


- job_name: info_logs
static_configs:
- targets:
- localhost
labels:
job: info_logs
job: ${MONITORING_PROFILE}_info_logs
__path__: /log/info/*.log
pipeline_stages:
- json:
expressions:
timestamp: timestamp
level: level
logger: logger
httpMethod: httpMethod
requestId: requestId
requestUri: requestUri
requestMethod: requestMethod
statusCode: statusCode
sourceClass: sourceClass
sourceMethod: sourceMethod
exceptionClass: exceptionClass
exceptionMessage: exceptionMessage
module: module
msg: message
environment: environment
- labels:
level:
logger:
httpMethod:
requestUri:
statusCode:
sourceClass:
sourceMethod:
exceptionClass:
exceptionMessage:
module:
environment:
- timestamp:
source: timestamp
Expand All @@ -94,47 +75,27 @@ scrape_configs:
- targets:
- localhost
labels:
job: warn_logs
job: ${MONITORING_PROFILE}_warn_logs
__path__: /log/warn/*.log
pipeline_stages:
- json:
expressions:
timestamp: timestamp
level: level
logger: logger
httpMethod: httpMethod
requestId: requestId
requestUri: requestUri
requestMethod: requestMethod
statusCode: statusCode
sourceClass: sourceClass
sourceMethod: sourceMethod
exceptionClass: exceptionClass
exceptionMessage: exceptionMessage
module: module
msg: message
environment: environment
- labels:
level:
logger:
httpMethod:
requestUri:
statusCode:
sourceClass:
sourceMethod:
exceptionClass:
exceptionMessage:
module:
environment:
- timestamp:
source: timestamp
format: 2006-01-02T15:04:05.000
location: "Asia/Seoul"

- job_name: http_logs
static_configs:
- targets:
- localhost
labels:
job: http_logs
__path__: /var/log/nginx/*.log
pipeline_stages:
- regex:
expression: '^(?P<remote_addr>[^\s]+) - - \[(?P<timestamp>[^\]]+)\] "(?P<method>[A-Z]+) (?P<request>[^ ]+) HTTP/[^"]+" (?P<status>\d+) (?P<body_bytes_sent>\d+)'
4 changes: 0 additions & 4 deletions backend/src/main/java/com/cruru/DataLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static com.cruru.question.domain.QuestionType.LONG_ANSWER;
import static com.cruru.question.domain.QuestionType.MULTIPLE_CHOICE;
import static com.cruru.question.domain.QuestionType.SHORT_ANSWER;
import static com.cruru.question.domain.QuestionType.SINGLE_CHOICE;

import com.cruru.applicant.domain.Applicant;
Expand Down Expand Up @@ -109,9 +108,6 @@ private void runDataLoader() {
List<Applicant> applicants = List.of(lurgi, dobby, arrr, chocochip, myungoh, rush, nyangin, redpanda);
applicantRepository.saveAll(applicants);

Question essayQuestion = questionRepository.save(
new Question(SHORT_ANSWER, "좋아하는 숫자가 무엇인가요?", 1, false, applyForm));

Question question1 = questionRepository.save(
new Question(LONG_ANSWER, "효과적인 학습 방식과 경험", 1, false, applyForm)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,4 @@ public CruruCustomException(String message, HttpStatus status) {
super(message);
this.status = status;
}

public String statusCode() {
return status.toString();
}
}
7 changes: 7 additions & 0 deletions backend/src/main/java/com/cruru/advice/ExceptionCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cruru.advice;

@FunctionalInterface
public interface ExceptionCallback {

void handleException(Exception e);
}
120 changes: 72 additions & 48 deletions backend/src/main/java/com/cruru/advice/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -1,76 +1,100 @@
package com.cruru.advice;

import com.cruru.global.util.ExceptionLogger;
import jakarta.servlet.http.HttpServletRequest;
import com.cruru.global.util.MdcUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

private final UncatchedExceptionHandler handler;
private static final int STACK_TRACE_LIMIT = 5;

@ExceptionHandler(CruruCustomException.class)
public ResponseEntity<ProblemDetail> handleCustomException(CruruCustomException e) {
HttpServletRequest request = getCurrentHttpRequest();
ExceptionLogger.info(request, e);

public ResponseEntity<Object> handleCustomException(CruruCustomException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(e.getStatus(), e.getMessage());
return ResponseEntity.of(problemDetail).build();

return handleExceptionWithMdc(e, problemDetail,
ex -> log.info("CRURU_EXCEPTION [errorMessage = {}]", ex.getMessage())
);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ProblemDetail> handleUnexpectedException(Exception e, WebRequest request) {
ProblemDetail problemDetail = handleException(e, request);
HttpStatus statusCode = HttpStatus.valueOf(problemDetail.getStatus());
if (statusCode.is5xxServerError()) {
ExceptionLogger.error(problemDetail);
} else {
ExceptionLogger.warn(problemDetail);
}
ProblemDetail detailsToSend = ProblemDetail.forStatus(statusCode);
return ResponseEntity.of(detailsToSend).build();
public ResponseEntity<Object> handleUnexpectedException(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류입니다.");

return handleExceptionWithMdc(e, problemDetail,
ex -> log.error("SERVER_EXCEPTION [errorMessage = {}, stackTrace = {}]",
ex.getMessage(),
getLimitedStackTrace(ex))
);
}

private ProblemDetail handleException(Exception e, WebRequest request) {
try {
ProblemDetail problemDetail = (ProblemDetail) Objects.requireNonNull(handler.handleException(e, request))
.getBody();
problemDetail.setProperties(setDetails(getCurrentHttpRequest(), e, HttpStatus.INTERNAL_SERVER_ERROR));
return problemDetail;
} catch (Exception ex) {
return ProblemDetail.forStatusAndDetail(
HttpStatus.INTERNAL_SERVER_ERROR,
"예기치 못한 오류가 발생하였습니다."
);
private String getLimitedStackTrace(Exception e) {
StackTraceElement[] stackTraceElements = e.getStackTrace();

return Arrays.stream(stackTraceElements)
.limit(STACK_TRACE_LIMIT)
.map(StackTraceElement::toString)
.collect(Collectors.joining());
}

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException e,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request
) {
Map<String, String> validation = new HashMap<>();
for (FieldError fieldError : e.getFieldErrors()) {
validation.put(fieldError.getField(), fieldError.getDefaultMessage());
}
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, validation.toString());

return handleExceptionWithMdc(e, problemDetail,
ex -> log.warn("METHOD_ARGUMENT_EXCEPTION [errorMessage = {}]", validation)
);
}

private HttpServletRequest getCurrentHttpRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
@Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception e,
Object body,
HttpHeaders headers,
HttpStatusCode statusCode,
WebRequest request
) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(statusCode, "오류가 발생했습니다. 다시 시도해 주세요.");

return handleExceptionWithMdc(e, problemDetail,
ex -> log.warn("SPRING_BASIC_EXCEPTION [errorMessage = {}]", ex.getMessage())
);
}

private static Map<String, Object> setDetails(HttpServletRequest request, Exception exception, HttpStatus status) {
StackTraceElement origin = exception.getStackTrace()[0];
Map<String, Object> map = new HashMap<>();
map.put("httpMethod", request.getMethod());
map.put("requestUri", request.getRequestURI());
map.put("statusCode", status.toString());
map.put("sourceClass", origin.getClassName());
map.put("sourceMethod", origin.getMethodName());
map.put("exceptionClass", exception.getClass().getSimpleName());
map.put("exceptionMessage", exception.getMessage());
return map;
private ResponseEntity<Object> handleExceptionWithMdc(
Exception e,
ProblemDetail problemDetail,
ExceptionCallback callback
) {
MdcUtils.setMdcForException(e, problemDetail);
callback.handleException(e);
MDC.clear();
return ResponseEntity.of(problemDetail).build();
}
}
Loading

0 comments on commit f95f65b

Please sign in to comment.