원글 페이지 : 바로가기
이번에 팝콘메이트 하면서 통신할 때 에러 코드나 짤막한 에러 원인을 받아 볼 수 있게 하였는데, 그 정보들만 가지고 원인을 해결하지 못할 때가 있다 보니 리팩토링 할 겸 팀 공용 디스코드에 로그 전체를 볼 수 있는 시스템을 만들어 보려고 한다 먼저 팀이 사용하는 디스코드에서 웹후크를 만들려면 채널 설정 -> 연동 들어가서 웹후크 만들기를 누르면 된다! 간단한 작업이다 본격적으로 코드 구현에 대해 알아보자 (1) FeignClient 이용하는 방식 먼저 DiscordClient 클래스에 Controller 클래스에 메서드 짜주는 것처럼 인터셉터를 위한 메서드를 써준다 @FeignClient(
name = “discord-client”,
url = “웹후크 URL”,
configuration = DiscordFeignConfig.class)
public interface DiscordClient {
@PostMapping
void sendAlarm(@RequestBody DiscordMessage message);
} 그다음에 DiscordFeignConfig에다가 intercept하기 위한 Bean을 등록해 준다 public class DiscordFeignConfig{
@Bean
public RequestInterceptor requestInterceptor() {
return template -> template.header(“Content-Type”, “application/json;charset=UTF-8”);
}
} Discord 공식 문서에 나와있는 요청 바디는 {
“content”: “string”
“embeds”: [
{
“title”: “string”
“description”: “string”
},
…
]
} 이런 식으로 되어있어서 DTO 또한 똑같이 만들어 주었다 @Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class DiscordMessage {
private String content;
private List
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public static class Embed {
private String title;
private String description;
}
} 나는 따로 ErrorHandlerResponse를 만들어서 쓰고 있기 때문에 GlobalExceptionHandler이라는 파일을 따로 만들어서 사용하고 있어 통신할 때 처리해 주는 메서드에 “sendDiscordAlarm”메서드를 만들어 호출해 주었다 @ExceptionHandler(BaseErrorException.class)
public ResponseEntity
BaseErrorException e, HttpServletRequest request) {
log.error(“BaseErrorException”, e);
final ErrorReason errorReason = e.getErrorCode().getErrorReason();
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
if (!Arrays.asList(environment.getActiveProfiles()).contains(“local”)) {
sendDiscordAlarm(e, request);
}
return ResponseEntity.status(HttpStatus.valueOf(errorReason.getStatus()))
.body(errorResponse);
}
private void sendDiscordAlarm(Exception e, WebRequest request) {
discordClient.sendAlarm(createMessage(e, request));
}
private DiscordMessage createMessage(Exception e, WebRequest request) {
return DiscordMessage.builder()
.content(“# 🚨 에러 발생 🚨”)
.embeds(
List.of(
DiscordMessage.Embed.builder()
.title(“ℹ️ 정보”)
.description(
“### 🕖 발생 시간\n”
+ LocalDateTime.now()
+ “\n”
+ “### 🔗 요청 URL\n”
+ createRequestFullPath(request)
+ “\n”
+ “### 📄 Stack Trace\n”
+ ““`\n”
+ getStackTrace(e).substring(0, 1000)
+ “\n“`”)
.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();
} 여기서 중요한 점은 spring Profile을 사용하고 있다면 local에서 테스트하는 에러 로그들을 굳이 모두가 보는 디스코드 채널에 보낼 필요가 없으니 꼭 local profile이 아닐 때를 고려해서 코드를 짜줘야 한다!! if (!Arrays.asList(environment.getActiveProfiles()).contains(“local”)) {
sendDiscordAlarm(e, request);
} + 디스코드 채널의 HTTP 연결 허용을 꼭 해줘야 한다. 안 한다면 401 에러가 난다! 하지만 이렇게 Intercept방식으로 하면 통신할 때 쓰는 에러 Response까지 바뀌게 된다.. 그래서 그냥 Discord LogBack 형식으로 바꿔서 해보았다 (2) LogBack 방식 위에 디스코드 웹훅 성정은 그대로지만 이번엔 LogBack.xml파일을 설정해주어야 한다 Api 모듈의 Resource 디렉터리에 logback.xml파일을 만들어 주었다
나는 특히 Spring Profile을 “애용”하고 있는 개발자로서 logback에 spring profile을 지원해 주는 점이 너무 좋았다 이 파일만 추가해 주면 디스코드에 이런 식으로 자세한 로그까지 오는 것을 볼 수 있다 결론 Feign을 이용하는 방법보다 디스코드의 logback형식이 훨씬 더 리소스를 잡아먹지도 않고 나처럼 디스코드 연동 처음 해보는 사람한테 엄청 편할 것 같다 하지만 Feign의 장점으로는 굳이 gradle library를 사용할 필요 없이 api로 통신하면 되는 것이라서 케이스 바이 케이스라는 말이 항상 맞는 것 같다! 대규모 팀 프로젝트나 인원이 많을 때 특히 이러한 협업 툴 연동이 정말 유용할 것 같아 적용해 보았다 출처 https://velog.io/@qwe916/Discord%EB%A1%9C-Spring-Logback-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0 Discord로 Spring Logback 설정하기 Logback이란 log4j 이후에 출시된 Java 기반 Logging Framework 중 하나로 가장 널리 사용되고 있다. SLF4j 의 구현체이며 Spring Boot 환경이라면 별도의 dependency 추가 없이 기본적으로 포함되어 있다.application. velog.io + Feign으로 디스코드 연동하는 부분은 이 분 블로그 참고하면서 도움 많이 되었다 https://velog.io/@eomgerm/AvAb-Spring-Discord-Webhook%EC%9C%BC%EB%A1%9C-%EC%97%90%EB%9F%AC-%EC%83%81%ED%99%A9-%EC%95%8C%EB%A6%BC-%EB%B0%9B%EA%B8%B0 [AvAb] Spring + Discord Webhook으로 에러 상황 알림 받기 아브아브의 데모데이도 얼마 남지 않았습니다. 서버는 얼추 기능 개발이 종료되고 리팩터링할 것들을 찾아보고 있는데요. 그 중에서 프런트엔드와 소통하면서 겪었던 문제 상황을 자동화해 보 velog.io