Skip to content

Commit

Permalink
Merge pull request #75 from AdultOfNineteen/refactor/issue-74
Browse files Browse the repository at this point in the history
Refactor/issue 74
  • Loading branch information
imenuuu authored Jan 16, 2024
2 parents d030fe0 + eb7f498 commit f4365b8
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.wineyapi.common.aop;

import static com.example.wineycommon.constants.WineyStatic.*;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
Expand Down Expand Up @@ -33,6 +35,9 @@ public void beforeLogic(JoinPoint joinPoint) throws Throwable {
Method method = methodSignature.getMethod();
String methodName = getMethodName(method);

if(IGNORE_METHODS.contains(methodName)) {
return;
}
log.info("==========================LOG_START==========================");

log.info("logging start method = {}", methodName);
Expand Down Expand Up @@ -60,8 +65,10 @@ private String getMethodName(Method method) {
@After("controller()")
public void afterLogic(JoinPoint joinPoint) throws Throwable {
Method method = getMethod(joinPoint);

String methodName = getMethodName(method);
if(IGNORE_METHODS.contains(methodName)) {
return;
}

log.info("logging finish method = {}", methodName);

Expand All @@ -71,9 +78,10 @@ public void afterLogic(JoinPoint joinPoint) throws Throwable {
@AfterReturning(value = "controller()", returning = "returnObj")
public void afterReturnLog(JoinPoint joinPoint, Object returnObj) {
Method method = getMethod(joinPoint);

String methodName = getMethodName(method);

if(IGNORE_METHODS.contains(methodName)) {
return;
}
if (returnObj != null) {
log.info("========================RETURN_LOG============================");
log.info("method name = {}", methodName);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package com.example.wineycommon.exception;
package com.example.wineyapi.config;

import com.example.wineycommon.reponse.CommonResponse;
import com.example.wineycommon.service.SlackService;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -16,23 +25,24 @@
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import com.example.wineyapi.security.JwtFilter;
import com.example.wineycommon.exception.BaseDynamicException;
import com.example.wineycommon.exception.BaseException;
import com.example.wineycommon.exception.UserException;
import com.example.wineycommon.exception.errorcode.CommonResponseStatus;
import com.example.wineycommon.reponse.CommonResponse;
import com.example.wineyinfrastructure.slack.service.SlackService;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@RestControllerAdvice
public class ExceptionAdvice{
public class ExceptionAdvice {
private final SlackService slackService;

@ExceptionHandler(ConstraintViolationException.class)
Expand Down Expand Up @@ -155,14 +165,34 @@ public ResponseEntity onUserException(UserException userException,

@ExceptionHandler(value = Exception.class)
public ResponseEntity onException(Exception exception, @AuthenticationPrincipal User user,
HttpServletRequest request) {
getExceptionStackTrace(exception, user, request);
if(user==null){
slackService.sendMessage("로그인 되지 않은 유저", exception, request);
HttpServletRequest request) throws IOException {
HttpServletRequest httpServletRequest = unwrapHttpServletRequest(request);

final Long userId = user != null ? Long.valueOf(user.getUsername()) : null;

getExceptionStackTrace(exception, user, httpServletRequest);
log.error("INTERNAL_SERVER_ERROR", exception);

CommonResponseStatus internalServerError = CommonResponseStatus._INTERNAL_SERVER_ERROR;
if (userId == null) {
slackService.sendMessage("로그인 되지 않은 유저", exception, httpServletRequest);
} else {
slackService.sendMessage(String.valueOf(userId), exception, httpServletRequest);
}

return new ResponseEntity<>(CommonResponse.onFailure(internalServerError.getCode(), internalServerError.getMessage(), null), null, internalServerError.getHttpStatus());
}

private HttpServletRequest unwrapHttpServletRequest(HttpServletRequest request) {
if (request instanceof ContentCachingRequestWrapper) {
return request;
} else if (request instanceof ResourceUrlEncodingFilter) {
return new ContentCachingRequestWrapper(request);
} else if (request instanceof HttpServletRequest){
return new ContentCachingRequestWrapper(request);
}
else{
slackService.sendMessage(user.getUsername(), exception, request);
else {
return request;
}
return new ResponseEntity<>(CommonResponse.onFailure("500", exception.getMessage(), null), null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.wineycommon.constants;

import java.util.List;

import org.springframework.data.redis.connection.RedisServer;

public class WineyStatic {
Expand Down Expand Up @@ -43,4 +45,6 @@ public class WineyStatic {
public static final String TASTE_DISCOVERY = "TASTE_DISCOVERY";

public static final Integer NON_ALCOHOLIC_INDEX = 11;

public static final List<String> IGNORE_METHODS = List.of(new String[]{"healthCheck", ""});
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.wineycommon.config;
package com.example.wineyinfrastructure.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package com.example.wineycommon.constants;
package com.example.wineyinfrastructure.slack.constants;

public class SlackStatic {
public static final String EXCEPTION_CLASS_LABEL = "exception class : ";
public static final String CODE_BLOCK_START = "```";
public static final String CODE_BLOCK_END = "```";
public static final String USER_LABEL = "사용자 : ";
public static final String PROFILE_LABEL = "실행중인 환경 : ";
public static final String SERVER_LABEL = "실행중인 서버 : ";
public static final String URI_LABEL = "요청 URI : ";
public static final String SERVER_LABEL = "요청 받은 서버 + URI : ";
public static final String EXCEPTION_MESSAGE_LABEL = "서버 에러 매시지 : ";
public static final String METHOD_LABEL = "request method : ";
public static final String QUERY_STRING_LABEL = "request query string : ";
public static final String REMOTE_ADDR_LABEL = "request remote addr : ";
public static final String REMOTE_HOST_LABEL = "request remote host : ";
public static final String REMOTE_PORT_LABEL = "request remote port : ";
public static final String SERVER_PORT_LABEL = "request server port : ";
public static final String SERVLET_PATH_LABEL = "request servlet path : ";
public static final String EXCEPTION_LABEL = "request exception : ";
public static final String IP_LABEL = "요청 IP : ";
public static final String EXCEPTION_CLASS_MESSAGE_VALUE = "Error occurred in class : %s - at line : %s";
public static final String UNKNOWN_EXCEPTION_CLASS_VALUE = "Unknown Exception";
public static final String SLACK_IMG_URL = "https://avatars.slack-edge.com/2024-01-11/6460804813748_57623dce3b29216a9aa8_48.png";
public static final String SLACK_USER_NAME = "서버 에러 알림";
public static final String UNKNOWN_HOST_EXCEPTION_MESSAGE = "올바른 슬랙 URL이 아닙니다.";
public static final int MAX_LEN = 1000;

}
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
package com.example.wineycommon.service;
package com.example.wineyinfrastructure.slack.converter;

import static com.example.wineycommon.constants.SlackStatic.*;

import static com.example.wineyinfrastructure.slack.constants.SlackStatic.*;

import javax.servlet.http.HttpServletRequest;

import com.slack.api.webhook.Payload;

public class SlackConverter {

public static String errorToSlackMessage(String user, HttpServletRequest request, Exception exception, String profile) {
public static String errorToSlackMessage(String user, HttpServletRequest request, Exception exception, String profile,
String url, String method, String errorMessage, String errorStack, String errorUserIP) {
StringBuilder sb = new StringBuilder();
sb.append(CODE_BLOCK_START);
appendLabelAndValue(sb, USER_LABEL, user);
appendLabelAndValue(sb, PROFILE_LABEL, profile);
appendLabelAndValue(sb, SERVER_LABEL, request.getServerName());
appendLabelAndValue(sb, URI_LABEL, request.getRequestURI());
appendLabelAndValue(sb, METHOD_LABEL, request.getMethod());
appendLabelAndValue(sb, SERVER_LABEL, url);
appendLabelAndValue(sb, METHOD_LABEL, method);
appendLabelAndValue(sb, QUERY_STRING_LABEL, request.getQueryString());
appendLabelAndValue(sb, EXCEPTION_CLASS_LABEL, getErrorOccurredClassName(exception));
appendLabelAndValue(sb, REMOTE_ADDR_LABEL, request.getRemoteAddr());
appendLabelAndValue(sb, REMOTE_HOST_LABEL, request.getRemoteHost());
appendLabelAndValue(sb, REMOTE_PORT_LABEL, Integer.toString(request.getRemotePort()));
appendLabelAndValue(sb, SERVER_PORT_LABEL, Integer.toString(request.getServerPort()));
appendLabelAndValue(sb, SERVLET_PATH_LABEL, request.getServletPath());
appendLabelAndValue(sb, EXCEPTION_LABEL, exception.getMessage());
appendLabelAndValue(sb, EXCEPTION_LABEL, errorMessage);
appendLabelAndValue(sb, EXCEPTION_MESSAGE_LABEL, errorStack);
appendLabelAndValue(sb, IP_LABEL, errorUserIP);
sb.append(CODE_BLOCK_END);
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
package com.example.wineycommon.service;
package com.example.wineyinfrastructure.slack.service;


import static com.example.wineycommon.constants.SlackStatic.*;
import static com.example.wineyinfrastructure.slack.constants.SlackStatic.*;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.util.ContentCachingRequestWrapper;

import com.example.wineyinfrastructure.slack.converter.SlackConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.slack.api.Slack;
import com.slack.api.webhook.Payload;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@RequiredArgsConstructor
@Slf4j
public class SlackService {
@Value("${slack.webhook-url}")
private String webhookUrl;

@Value("${spring.config.activate.on-profile}")
private String profile;
private final ObjectMapper objectMapper;


@Async("slack-notification")
public void sendMessage(String user, Exception exception, HttpServletRequest request){
public void sendMessage(String user, Exception exception, HttpServletRequest cachingRequest) throws
IOException {
final String url = cachingRequest.getRequestURL().toString();
final String method = cachingRequest.getMethod();
final String errorMessage = exception.getMessage();
String errorStack = getErrorStack(exception);
final String errorUserIP = cachingRequest.getRemoteAddr();

final Slack slack = Slack.getInstance();
final String message = SlackConverter.errorToSlackMessage(user, request, exception, profile);
final String message = SlackConverter.errorToSlackMessage(user, cachingRequest, exception, profile, url, method, errorMessage, errorStack, errorUserIP);
final Payload payload = SlackConverter.convertToPayload(message);
try {
String responseBody = slack.send(webhookUrl, payload).getBody();
Expand All @@ -43,4 +56,10 @@ public void sendMessage(String user, Exception exception, HttpServletRequest req
throw new RuntimeException(e);
}
}

private String getErrorStack(Throwable throwable) {
String exceptionAsString = Arrays.toString(throwable.getStackTrace());
int cutLength = Math.min(exceptionAsString.length(), MAX_LEN);
return exceptionAsString.substring(0, cutLength);
}
}

0 comments on commit f4365b8

Please sign in to comment.