문제 상황
프로젝트를 하면서 우리도 모르게 예외가 터지는 경우가 많아서 실제로 기능에 버그가 있는데 빠르게 캐치하지 못한 적이 많았다.
예외가 발생했을 때 개발자인 우리에게 알려줄 수 있으면 좋겠다고 생각이 들었다.
Github 이슈 자동 등록
스모디 팀 슬랙 채널이 존재한다. 프로젝트 깃허브에 PR, Issue 등록, Merge 등의 이벤트가 발생하면 슬랙 채널에 메시지가 오도록 Guthub 앱을 등록한 상태다.
Create an Issue
POST https://api.github.com/repos/woowacourse-teams/2022-smody/issues
Autuorization: token {accessToken}
{
"title":"이슈 제목",
"body":"이슈 바디",
"assignees":["ldk980130"],
"labels":["에러 해결", "백엔드"]
}
위 형태로 HTTP 요청을 하면 명시한 repo에 이슈가 자동으로 등록이 된다. 다만 api를 사용하려면 Authorization 헤더에 accessToken이 필요한데 이는 다음의 과정을 거쳐 쉽게 얻을 수 있다.
Access Token 얻기
1. Seetings에 들어간다.
2. 왼쪽 바 최하단에 Developers settings에 들어간다.
3. Personal access tokens 탭에서 Generate new token 버튼을 누른다.
4. NOTE에 간단한 설명을 입력하고 repo에만 체크를 해준 뒤 생성한다.
5. 생성한 뒤 나오는 페이지에 token이 명시되는데 잘 복사해 둔다
자바 코드에서 api 요청하기
우선 application.properties에 방금 받아 온 accessToken을 넣어둔다.
그리고 Exception을 매개변수로 받아 이슈 내용을 채워서 RestTemplate을 통해 이슈를 생성하는 로직을 짠다.
아래 메서드에 Exception을 넣어주면 해당 Exception의 정보가 Issue 제목과 본문에 들어가게 된다.
@Component
@RequiredArgsConstructor
public class GithubIssueGenerator {
private static final String REPO_URL = "https://api.github.com/repos/woowacourse-teams/2022-smody/issues";
private static final List ASSIGNEES = List.of("ldk980130", "bcc0830", "jojogreen91", "tonic523");
private static final List LABELS = List.of("장애", "에러 해결", "백엔드");
private static final MediaType JSON_MEDIA_TYPE = new MediaType("application", "json", StandardCharsets.UTF_8);
@Value("${github.access.token}")
private String accessToken;
private final ObjectMapper objectMapper;
private final RestTemplate restTemplate;
public void create(Exception exception) {
// api 요청
restTemplate.exchange(
REPO_URL,
HttpMethod.POST,
new HttpEntity<>(createRequestJson(exception), setAuthorization()),
String.class
);
}
// DTO 객체를 JSON 문자열로 변환
private String createRequestJson(Exception exception) {
return parseJsonString(new IssueCreateRequest(
"[ERROR] 서버 장애 발생 " + exception.getMessage(),
createIssueBody(exception),
ASSIGNEES,
LABELS
));
}
private String parseJsonString(IssueCreateRequest request) {
try {
return objectMapper.writeValueAsString(request);
} catch (JsonProcessingException e) {
throw new BusinessException(ExceptionData.DATA_INTEGRITY_ERROR);
}
}
// 발생한 예외의 stackTrace를 마크다운 코드 블럭으로 감싸서 작성
private String createIssueBody(Exception exception) {
StringWriter stringWriter = new StringWriter();
exception.printStackTrace(new PrintWriter(stringWriter));
return "```\\n" + stringWriter + "\\n```";
}
// Authorization 헤더에 accessToken 입력
private HttpHeaders setAuthorization() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Authorization", "token " + accessToken);
httpHeaders.setContentType(JSON_MEDIA_TYPE);
return httpHeaders;
}
}
예상치 못한 예외 상황에 자동으로 api 호출
현재 ControllerAdvice 클래스에서 비즈니스 로직상 자연스럽게 발생하는 예외에 대해서는 BusinessException이라고 명시하고 로그를 찍어주고 있다.
BusinessException이 아닌 Exception은 우리가 예상치 못한 예외라는 뜻이고 이는 곧 버그다.
그래서 BusinessException 이외의 모든 예외를 잡은 @ExceptionHandler를 만들고 거기서 GithubIssueGenerator.create()를 호출하도록 했다.
하지만 이렇게만 하면 로컬 환경이나 QA 환경 서버에서 버그가 났을 때도 자동으로 이슈가 등록된다. 운영 서버에서만 동작하도록 코드를 수정할 필요가 있다.
우선 클래스에서 운영 환경 Profile 이름인 “prod”를 상수 선언하고 org.springframework.core.env.Environment를 빈 주입받도록 했다. Enviroment 빈을 통해 현재 실행되고 있는 환경의 ActiveProfile을 알 수 있다.
아래와 같이 ActiveProfile이 prod일 때만 동작하도록 if문을 간단히 추가하는 것 만으로 운영 환경에서만 동작하게 되었다.
결과
테스트를 해보니 이슈도 잘 등록되고 이슈 발생에 따라 슬랙에도 알림이 와 있는 것을 확인했다.
'우아한테크코스 > 프로젝트-SMODY' 카테고리의 다른 글
[Spring] 동시성과 예외, 그리고 트랜잭션 (0) | 2022.10.01 |
---|---|
[Spring] 알림 기능 비동기 처리하기 (0) | 2022.09.17 |
이벤트 트랜잭션 분리와 테스트에서의 @Transactional 문제 (0) | 2022.08.30 |
결합은 낮추고 전략은 다양하게, 알림 기능 적용기 (0) | 2022.08.15 |
[JPA] 조회 쿼리 N+1 문제 해결 (0) | 2022.07.10 |