본문 바로가기
Spring

스프링에서 실시간 에러 로그를 Slack으로 받는 방법

by 이숴 2023. 11. 22.
반응형

플랫폼을 운영하면서 실시간으로 발생하는 에러를 빠르게 캐치하고 대응하려면 개발자에게 빠르게 그 사실을 알려야합니다.

그래서 일반적으로 슬랙이나 디스코드와 같은 플랫폼으로 알림을 받아 문제를 빠르게 인식할 수 있도록 구성하는데요.

 

저는 스프링 서버에서 슬랙으로 로그를 받는 방법을 구현해보았습니다.

 

우선 먼저 슬랙에 웹훅 봇을 추가해야합니다.

본인이 웹훅을 추가할 워크스페이스에 다음과 같이 앱 카테고리를 선택합니다.

앱 카테고리 선택

 

 

 

이후, 검색창에 webhook이라고 검색하시면 incoming webhooks 앱이 있습니다. 해당 앱의 추가를 누르시면

웹훅 앱 추가

 

 

 

웹훅 설명

이 웹훅을 Slack에 추가 를 눌러봅시다.

 

 

그다음 웹훅 봇을 추가할 채널을 선택하고 추가 버튼을 클릭합니다.

워크스페이스 채널 선택

 

 

그러면 이제 웹훅의 설정 화면이 나옵니다.

그 설정 중에 webhook url 부분이 있는데, 이 url을 통해 서버와 연결을 한다고 생각하시면 됩니다.

웹훅 URL

 

 

이제부터는 스프링부트에서 작업을 해야합니다.

 

 

먼저 슬랙의 의존성을 추가합니다. (의존성 정보:  https://mvnrepository.com/artifact/com.slack.api/slack-api-client)

슬랙 의존성

 

 

그다음 환경 변수로 사용할 URL을 설정 파일에 포함시킵니다.

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

 

action-slack - GitHub Marketplace

You can notify slack of GitHub Actions

github.com

 

만약에 이전 단계가 성공한다면 알림의 이름은 배포 성공이 될 것이고, 실패한다면 배포 실패가 될 것입니다.

이후 배포를 진행하면..

 

 

의도적으로 실패를 테스트해보실 분께서는

- name: 의도적 실패 유발
  run: exit 1

 

이전 단계에 이 코드를 추가하여 테스트하시면 될 것 같습니다.

 

참고

https://jojoldu.tistory.com/552

 

Slack Webhook API 생성하기

요즘 대부분의 개발도구들은 Slack과의 통합 (Integration)을 지원하지만, 여전히 미지원 하는 도구들도 많습니다. 이런 미지원 도구들을 Slack에 연동할때 Slack Webhook을 사용합니다. 저도 종종 사용하

jojoldu.tistory.com

https://github.com/marketplace/actions/action-slack

 

action-slack - GitHub Marketplace

You can notify slack of GitHub Actions

github.com

https://kth990303.tistory.com/438

 

[Spring] 서버 에러 시 Slack Api Client로 슬랙에 알림 보내기

해당 글에서는 slack-api-client 라이브러리 선정 이유, @ControllerAdvice에서 슬랙 연동 방법에 대해 다룹니다. 사이드 프로젝트 `모카콩`의 Wiki에 작성한 글에 해당된다. 해당 프로젝트 github: https://github

kth990303.tistory.com

https://mvnrepository.com/artifact/com.slack.api/slack-api-client

 

반응형

댓글