플랫폼을 운영하면서 실시간으로 발생하는 에러를 빠르게 캐치하고 대응하려면 개발자에게 빠르게 그 사실을 알려야합니다.
그래서 일반적으로 슬랙이나 디스코드와 같은 플랫폼으로 알림을 받아 문제를 빠르게 인식할 수 있도록 구성하는데요.
저는 스프링 서버에서 슬랙으로 로그를 받는 방법을 구현해보았습니다.
우선 먼저 슬랙에 웹훅 봇을 추가해야합니다.
본인이 웹훅을 추가할 워크스페이스에 다음과 같이 앱 카테고리를 선택합니다.
이후, 검색창에 webhook이라고 검색하시면 incoming webhooks 앱이 있습니다. 해당 앱의 추가를 누르시면
이 웹훅을 Slack에 추가 를 눌러봅시다.
그다음 웹훅 봇을 추가할 채널을 선택하고 추가 버튼을 클릭합니다.
그러면 이제 웹훅의 설정 화면이 나옵니다.
그 설정 중에 webhook url 부분이 있는데, 이 url을 통해 서버와 연결을 한다고 생각하시면 됩니다.
이제부터는 스프링부트에서 작업을 해야합니다.
먼저 슬랙의 의존성을 추가합니다. (의존성 정보: https://mvnrepository.com/artifact/com.slack.api/slack-api-client)
그다음 환경 변수로 사용할 URL을 설정 파일에 포함시킵니다.
그 다음 슬랙에 메세지를 보낼 로직을 작성합니다. 저는 따로 컴포넌트로 나누어 작성하였습니다.
@Slf4j
@Component
public class SlackService {
private final Slack slackClient = Slack.getInstance();
@Value("${slack.webhook.url}")
private String webhookUrl;
// slack cient에 메세지 작성, 전송 로직
public void sendSlackAlertLog(CustomException e, HttpServletRequest request) {
try {
slackClient.send(webhookUrl, payload(p -> p
.text("\uD83D\uDEA8" +
" 서버에 에러가 감지되었습니다. 즉시 확인이 필요합니다. " +
"\uD83D\uDEA8")
.attachments(
List.of(generateSlackAttachment(e, request))
)
));
} catch (IOException slackError) {
// 실제 에러 로그가 아닌 slack과의 통신 장애이기 때문에 error가 아닌 debug로 log
log.debug("Slack 통신 과정에 예외 발생");
}
}
// 메세지 내에 첨부될 정보를 추가, 생성
private Attachment generateSlackAttachment(CustomException e, HttpServletRequest request) {
String requestTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(LocalDateTime.now());
String xffHeader = request.getHeader("X-FORWARDED-FOR");
return Attachment.builder()
.color("ff0000")
.title(requestTime + " 발생 에러 로그")
.fields(List.of(
generateSlackField("Request IP", xffHeader == null ? request.getRemoteAddr() : xffHeader),
generateSlackField("Request URL", request.getRequestURL() + " " + request.getMethod()),
generateSlackField("Error Code", e.getErrorCode().getStatus().toString()),
generateSlackField("Error Message", e.getErrorCode().getMessage())
)
)
.build();
}
// 슬랙의 단락별 제목과 내용을 구성하는 객체 생성
private Field generateSlackField(String title, String value) {
return Field.builder()
.title(title)
.value(value)
.valueShortEnough(false)
.build();
}
}
이렇게 작성된 로직을 쓰고싶은 곳에 추가하여 사용하면 됩니다.
저는 에러가 발생할 때마다 메세지를 생성하고 싶어서 전역 exception 핸들러에서 추가하여 사용하고 있습니다.
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {
private final SlackService slackService;
// 예시 코드
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException e, HttpServletRequest request){
ErrorCode errorCode = e.getErrorCode();
slackService.sendSlackAlertLog(e, request);
return ResponseEntity.status(errorCode.getStatus()).body( new ErrorResponse(errorCode.getMessage()));
}
}
이렇게 설정하고 일부로 에러를 발생시키면..
다음과 같이 슬랙 채널에서 에러 알림을 받을 수 있습니다!
추가
에러 알림 이외에 배포시에도 성공 실패 알림을 받게 할수도 있습니다.
저는 Github Actions를 기준으로 작성해보겠습니다.
우선 알림을 추가할 프로젝트의 secret으로 웹훅 url을 추가합니다.
이후 배포단계에 다음 코드를 추가합니다.
- name: 배포 알림 발송
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
author_name: 배포 ${{ job.status == 'success' && '성공' || '실패' }}
fields: repo, commit, message, author
mention: here
if_mention: failure,cancelled
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: always()
출처: https://github.com/marketplace/actions/action-slack
만약에 이전 단계가 성공한다면 알림의 이름은 배포 성공이 될 것이고, 실패한다면 배포 실패가 될 것입니다.
이후 배포를 진행하면..
의도적으로 실패를 테스트해보실 분께서는
- name: 의도적 실패 유발
run: exit 1
이전 단계에 이 코드를 추가하여 테스트하시면 될 것 같습니다.
참고
https://jojoldu.tistory.com/552
https://github.com/marketplace/actions/action-slack
https://kth990303.tistory.com/438
https://mvnrepository.com/artifact/com.slack.api/slack-api-client
'Spring' 카테고리의 다른 글
환경변수 @ConfigurationProperties로 간단히 관리하기 (with Kotlin) (1) | 2024.01.30 |
---|---|
스프링에서 gpt api 사용해보기 (0) | 2024.01.16 |
스프링에서 실시간 에러 로그를 Discord로 받는 방법 (1) | 2023.12.10 |
JPA의 정적쿼리와 동적쿼리의 차이점 (0) | 2023.06.06 |
@Validated, @Valid와 @Column으로 나뉘는 유효성 검증 (0) | 2023.03.22 |
댓글