이번에 인프런 프리온보딩을 진행하면서 발생하는 Log를 슬랙으로 전송시켜 로그 파악을 편리하게 진행해야 한다는 생각이 들어서 슬랙 api를 사용해 보았다.
슬랙 설정
1. 채널을 생성하고 우클릭 -> 채널 세부정보 보기 -> 통합 -> 앱 추가
2. incoming webhooks 설치
해당 WebHooks를 다운로드.
WebHook은 웹 애플리케이션에서 특정 이벤트를 발생시켰을 때, 다른 시스템에게 자동으로 알림을 보내는 방식이다.
3. 웹훅 url
추가를 완료하면 위 화면처럼 웹훅 URL을 발급받을 수 있다.
아래 슬랙 홈페이지를 가면 의존성 주입을 위한 코드가 존재.
https://slack.dev/java-slack-sdk/guides/web-api-client-setup
Installation | Slack SDK for Java
API Client Installation The first step to using the Slack API client is installing the slack-api-client module. This guide shows you how to set up using Maven, Gradle, and by building from source on your own. Prerequisites Installing OpenJDK 8 or higher LT
slack.dev
2024/06/09 기준 아래가 최신 버전입니다.
implementation("com.slack.api:slack-api-client:1.39.3")
이후 Slack을 보낼 서비스를 하나 생성.
@Service
@Slf4j
public class SlackMsgService {
@Value("${spring.slack.webhook}")
private String webhookUrl;
public boolean sendMsg() {
Slack slack = Slack.getInstance();
Payload payload = Payload.builder().text("asdasfas").build();
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생.");
throw new RuntimeException(e);
}
return true;
}
}
yml은 spring:slack:webhook으로 경로를 만들어서 설정.
sendMsg() 메서드를 통해서 설정해 놓은 웹훅 URL로 메시지를 보내면 슬랙 채널로 메시지가 전송.
Slack 클래스를 보면 파라미터로 Payload를 따로 받고 있다.
처음에 간과하고 String으로 보냈다가 유효하지 않은 입력이 들어왔다고 응답이 와서 Payload를 통해 따로 텍스트 데이터를 생성해 주었다.
해당 서비스를 이용해 예외 발생 시점에 메서드를 실행시켰던 결과 아래처럼 메시지가 정상적으로 도착하는 것을 확인.
이제 입맛에 맞게 글로벌 핸들러에서 잡히는 Log를 슬랙 메시지로 보내주면 된다.
public class SlackMsgService {
@Value("${spring.slack.webhook}")
private String webhookUrl;
public boolean sendMsg(CommonException e, HttpServletRequest request) {
Slack slack = Slack.getInstance();
String message = buildMessage(e, request);
Payload payload = Payload.builder().text(message).build();
try {
slack.send(webhookUrl, payload);
} catch (IOException ioe) {
log.error("slack 메시지 발송 중 문제가 발생.");
throw new RuntimeException(ioe);
}
return true;
}
private String buildMessage(CommonException e, HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
sb.append(":exclamation: *Exception class* :exclamation:").append("\n")
.append("```").append(e.getClass().getName()).append("```").append("\n")
.append("*Request URI*").append("\n")
.append("```").append(request.getRequestURI()).append("```").append("\n")
.append("*Request Method*").append("\n")
.append("```").append(request.getMethod()).append("```").append("\n")
.append("*발생 시간*").append("\n")
.append("```").append(LocalDateTime.now()).append("```").append("\n")
.append("*이유*").append("\n")
.append("```").append(e.getExceptionMessage()).append("```").append("\n")
.append("*로그메시지*").append("\n")
.append("```").append(e.getLog()).append("```");
return sb.toString();
}
}
뭔가 엉성하긴 하지만 서버 배포해서 슬랙 메시지까지 정상적으로 오는 것을 확인.
그런데 문제는 에러가 발생하고 해당 슬랙 전송을 동기로 실행하다 보니 응답 시간이 조금 늦는 문제가 발생.
이것도 결국 비동기 스레드 풀을 만들어서 비동기로 처리를 진행하는 것이 좋다고 판단.
기존에도 Email 때문에 스레드풀을 만들어서 쓰고 있었는데 처음에는 하나의 스레드풀을 같이 이용할까 생각했지만
만약에 두 작업이 동시에 들어온다면?? 우선순위를 어떻게 따져줄까에 대한 문제가 있었다.
그래서 그냥 각자 스레드풀을 만들어서 사용.(아직도 적절한 스레드풀의 개수는 잘 모르겠습니다. 아마 평균 사용량에 따라 달라질 느낌)
@Configuration
public class AsyncConfig {
private static final int EMAIL_CORE_POOL_SIZE = 10;
private static final int EMAIL_MAX_POOL_SIZE = 30;
private static final int EMAIL_QUEUE_CAPACITY = 20;
private static final int SLACK_CORE_POOL_SIZE = 20;
private static final int SLACK_MAX_POOL_SIZE = 50;
private static final int SLACK_QUEUE_CAPACITY = 100;
@Bean
public Executor emailTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(EMAIL_CORE_POOL_SIZE);
executor.setMaxPoolSize(EMAIL_MAX_POOL_SIZE);
executor.setQueueCapacity(EMAIL_QUEUE_CAPACITY);
executor.setThreadNamePrefix("Email-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Bean
public Executor slackTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(SLACK_CORE_POOL_SIZE);
executor.setMaxPoolSize(SLACK_MAX_POOL_SIZE);
executor.setQueueCapacity(SLACK_QUEUE_CAPACITY);
executor.setThreadNamePrefix("Slack-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
이후 아래처럼 슬렉 메시지를 보내는 메서드에 비동기를 달아줘서 스레드풀을 이용하도록 변경.
@Async("slackTaskExecutor")
public void sendMsg(CommonException e, HttpServletRequest request) {
예외가 터져도 슬랙 메시지를 기다리느라 2~3초의 응답이 걸렸는데 지금은 비동기로 처리해서 따로 처리를 진행.
'프로젝트 > RESTAPI 추천 서비스' 카테고리의 다른 글
서비스 내에서 발생하는 쿼리를 분석하고 개선하기 (0) | 2024.06.12 |
---|---|
certbot SSL 인증서 갱신하기 (1) | 2024.06.11 |
매번 가져오는 유저를 공통으로 처리하기(Feat, Resolver) (1) | 2024.06.08 |
프로젝트 코드리뷰 (2) (0) | 2024.06.07 |