0. 이 글을 작성하는 이유
서비스를 운영 중 문제가 발생했을 때 slack으로 알람을 주기 위해 webhook이 가장 구현이 편해서 공유하고자 함
1. 준비 과정
실은 아래 2개의 문서를 참고하면 잘 된다. 역시 공식문서가 잘 되어있으면 개발자가 편하다.
https://slack.dev/java-slack-sdk/guides/web-api-client-setup
https://slack.dev/java-slack-sdk/guides/incoming-webhooks
우선 spring project를 하나 만들도록 하자.
내 프로젝트의 gradle은 아래와 같다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.hustle'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.slack.api:slack-api-client:1.30.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
단 하나 직접 추가해 준 부분은 'com.slack.api:slack-api-client' 라이브러리다. 슬랙 공식 도큐먼트에서 설명하는 api로 시중에 다른 라이브러리를 사용하는 것보다 이걸 사용하는 게 가장 정확하지 않을까 싶다.
이후 slack을 열어 앱을 추가해준다.
우선 앱에서 webhook을 검색한 후 Incoming WebHooks를 검색해서 추가 버튼을 누른다.
이후 알람을 받기 원하는(webhook추가를 원하는) 채널을 고른 후 수신 웹후크 통합 앱 추가 버튼을 누른다.
그러면 웹후크 URL이 나타나는데 이 URL로 우리는 요청을 보내 알람을 보내게 된다.
그러면 이제 메시지를 보내기 위해 코드를 작성해 보자. 해당 글은 실 환경처럼 하지는 않고 테스트 코드에서 마무리할 예정이다.
2. 코드 작성
@Service
@Slf4j
public class MsgService {
final String webhookUrl = "SLACK_URL";
public boolean sendMsg(){
Slack slack = Slack.getInstance();
String payload = "{\"text\":\"슬랙 메시지 테스트입니다.\"}";
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
}
우선 최대한 간단하게 테스트를 하기 위해 만들었다. webhookUrl 변수에는 방금 앱을 추가하고 얻은 웹후크 URL의 값을 넣어주면 된다.
@SpringBootTest
class MsgServiceTest {
@Autowired
private MsgService msgService;
@Test
void 메시지_전송_테스트(){
boolean result = msgService.sendMsg();
Assertions.assertEquals(result, true);
}
}
내 슬랙으로 잘 들어오는 것을 확인했다. 근데 이미지와 이름이 마음에 들지 않는다. 고쳐보도록 하자.
해당 앱의 구성 버튼을 누르면 설정할 수 있는 웹페이지로 안내해 준다.
잘 바뀐 것을 확인할 수 있다.
그러면 이제 조금만 더 나아가서 해당 url이 어떻게 사용되는 것이 가장 깔끔할지 개선을 해보자.
어딘가에 노출을 시키지 않고 외부 환경변수로 받는 것을 생각해 보았다.
slack:
webhook:
alertbot:
url: ${SLACK_WEBHOOK_URL}
이렇게 설정한 경우 SLACK_WEBHOOK_URL이라는 환경변수를 참조하게 된다.
IntelliJ에서는 런타임 환경에서 외부 환경변수를 주입해 주는 것처럼 설정을 할 수 있다.
다만 이 방식은 각 런타임마다 설정을 해주어야 하기 때문에 현재 나는 테스트 코드에 설정이 되었고 application을 동작시킬 시에는 application(필자의 경우 SlackMsgApplication)에 설정을 해주어야 한다.
이렇게 변경된 코드를 다시 살펴보자.
@Service
@Slf4j
public class MsgService {
@Value("${slack.webhook.alertbot.url}")
String webhookUrl;
public boolean sendMsg(){
Slack slack = Slack.getInstance();
String payload = "{\"text\":\"환경변수 변경 후 슬랙 메시지 테스트입니다.\"}";
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
}
여전히 잘 동작한다. 다만 이 코드 또한 payload를 외부에서 설정할 수 있게 바꾸는 게 가장 좋을 것이다.
@Service
@Slf4j
public class MsgService {
@Value("${slack.webhook.alertbot.url}")
String webhookUrl;
public boolean sendMsg(String key, String message){
Slack slack = Slack.getInstance();
String payload = makePayLoad(key, message);
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
private String makePayLoad(String key, String message){
return "{\"" + key + "\":\"" + message + "\"}";
}
}
@SpringBootTest
class MsgServiceTest {
@Autowired
private MsgService msgService;
@Test
void 메시지_전송_테스트() {
boolean result = msgService.sendMsg("text", "잘 돌아가는 코드입니다.");
Assertions.assertEquals(result, true);
}
}
3. 마치며
이렇게 해서 slack에 webhook을 추가하고 스프링에서 문제가 발생했을 때 메시지를 전달할 수 있는 환경을 만들어 보았다.
payload부분에는 커스텀을 통해 정말 다양하게 사용이 가능하다. 공식 문서를 참고하자. 아래 이미지는 위 구성을 눌렀을 때 나오는 도큐먼트이고 별도로 개발 문서를 첨부하도록 하겠다.
https://api.slack.com/messaging/webhooks
정말 유용한 기술 중 하나이며 실제 환경에서는 해당 코드에 대해 더욱 유연성을 가져갈 수 있는 코드로 개선해서 사용하기를 바란다.
'JAVA > spring' 카테고리의 다른 글
테스트 진행하기(Entity 기본과 약간의 Repository를 곁들인) (0) | 2023.08.05 |
---|---|
Spring + discord webhook 연동하기 (2) | 2023.07.13 |
SpringBoot 3.x 버전에서 junit5 를 사용해서 테스트하는데 왜 RunWith가 먹히지 않고 필요가 없는가? (0) | 2023.07.07 |
스프링 데이터 jpa 공식 문서 읽으면서 끄적끄적 (0) | 2023.04.23 |
spring method 요청에 대해 핸들링하기 (0) | 2023.03.13 |
0. 이 글을 작성하는 이유
서비스를 운영 중 문제가 발생했을 때 slack으로 알람을 주기 위해 webhook이 가장 구현이 편해서 공유하고자 함
1. 준비 과정
실은 아래 2개의 문서를 참고하면 잘 된다. 역시 공식문서가 잘 되어있으면 개발자가 편하다.
https://slack.dev/java-slack-sdk/guides/web-api-client-setup
https://slack.dev/java-slack-sdk/guides/incoming-webhooks
우선 spring project를 하나 만들도록 하자.
내 프로젝트의 gradle은 아래와 같다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.hustle'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.slack.api:slack-api-client:1.30.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
단 하나 직접 추가해 준 부분은 'com.slack.api:slack-api-client' 라이브러리다. 슬랙 공식 도큐먼트에서 설명하는 api로 시중에 다른 라이브러리를 사용하는 것보다 이걸 사용하는 게 가장 정확하지 않을까 싶다.
이후 slack을 열어 앱을 추가해준다.
우선 앱에서 webhook을 검색한 후 Incoming WebHooks를 검색해서 추가 버튼을 누른다.
이후 알람을 받기 원하는(webhook추가를 원하는) 채널을 고른 후 수신 웹후크 통합 앱 추가 버튼을 누른다.
그러면 웹후크 URL이 나타나는데 이 URL로 우리는 요청을 보내 알람을 보내게 된다.
그러면 이제 메시지를 보내기 위해 코드를 작성해 보자. 해당 글은 실 환경처럼 하지는 않고 테스트 코드에서 마무리할 예정이다.
2. 코드 작성
@Service
@Slf4j
public class MsgService {
final String webhookUrl = "SLACK_URL";
public boolean sendMsg(){
Slack slack = Slack.getInstance();
String payload = "{\"text\":\"슬랙 메시지 테스트입니다.\"}";
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
}
우선 최대한 간단하게 테스트를 하기 위해 만들었다. webhookUrl 변수에는 방금 앱을 추가하고 얻은 웹후크 URL의 값을 넣어주면 된다.
@SpringBootTest
class MsgServiceTest {
@Autowired
private MsgService msgService;
@Test
void 메시지_전송_테스트(){
boolean result = msgService.sendMsg();
Assertions.assertEquals(result, true);
}
}
내 슬랙으로 잘 들어오는 것을 확인했다. 근데 이미지와 이름이 마음에 들지 않는다. 고쳐보도록 하자.
해당 앱의 구성 버튼을 누르면 설정할 수 있는 웹페이지로 안내해 준다.
잘 바뀐 것을 확인할 수 있다.
그러면 이제 조금만 더 나아가서 해당 url이 어떻게 사용되는 것이 가장 깔끔할지 개선을 해보자.
어딘가에 노출을 시키지 않고 외부 환경변수로 받는 것을 생각해 보았다.
slack:
webhook:
alertbot:
url: ${SLACK_WEBHOOK_URL}
이렇게 설정한 경우 SLACK_WEBHOOK_URL이라는 환경변수를 참조하게 된다.
IntelliJ에서는 런타임 환경에서 외부 환경변수를 주입해 주는 것처럼 설정을 할 수 있다.
다만 이 방식은 각 런타임마다 설정을 해주어야 하기 때문에 현재 나는 테스트 코드에 설정이 되었고 application을 동작시킬 시에는 application(필자의 경우 SlackMsgApplication)에 설정을 해주어야 한다.
이렇게 변경된 코드를 다시 살펴보자.
@Service
@Slf4j
public class MsgService {
@Value("${slack.webhook.alertbot.url}")
String webhookUrl;
public boolean sendMsg(){
Slack slack = Slack.getInstance();
String payload = "{\"text\":\"환경변수 변경 후 슬랙 메시지 테스트입니다.\"}";
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
}
여전히 잘 동작한다. 다만 이 코드 또한 payload를 외부에서 설정할 수 있게 바꾸는 게 가장 좋을 것이다.
@Service
@Slf4j
public class MsgService {
@Value("${slack.webhook.alertbot.url}")
String webhookUrl;
public boolean sendMsg(String key, String message){
Slack slack = Slack.getInstance();
String payload = makePayLoad(key, message);
try {
WebhookResponse response = slack.send(webhookUrl, payload);
System.out.println(response);
} catch (IOException e) {
log.error("slack 메시지 발송 중 문제가 발생했습니다.", e.toString());
throw new RuntimeException(e);
}
return true;
}
private String makePayLoad(String key, String message){
return "{\"" + key + "\":\"" + message + "\"}";
}
}
@SpringBootTest
class MsgServiceTest {
@Autowired
private MsgService msgService;
@Test
void 메시지_전송_테스트() {
boolean result = msgService.sendMsg("text", "잘 돌아가는 코드입니다.");
Assertions.assertEquals(result, true);
}
}
3. 마치며
이렇게 해서 slack에 webhook을 추가하고 스프링에서 문제가 발생했을 때 메시지를 전달할 수 있는 환경을 만들어 보았다.
payload부분에는 커스텀을 통해 정말 다양하게 사용이 가능하다. 공식 문서를 참고하자. 아래 이미지는 위 구성을 눌렀을 때 나오는 도큐먼트이고 별도로 개발 문서를 첨부하도록 하겠다.
https://api.slack.com/messaging/webhooks
정말 유용한 기술 중 하나이며 실제 환경에서는 해당 코드에 대해 더욱 유연성을 가져갈 수 있는 코드로 개선해서 사용하기를 바란다.
'JAVA > spring' 카테고리의 다른 글
테스트 진행하기(Entity 기본과 약간의 Repository를 곁들인) (0) | 2023.08.05 |
---|---|
Spring + discord webhook 연동하기 (2) | 2023.07.13 |
SpringBoot 3.x 버전에서 junit5 를 사용해서 테스트하는데 왜 RunWith가 먹히지 않고 필요가 없는가? (0) | 2023.07.07 |
스프링 데이터 jpa 공식 문서 읽으면서 끄적끄적 (0) | 2023.04.23 |
spring method 요청에 대해 핸들링하기 (0) | 2023.03.13 |