Discord Webhook을 활용한 실시간 에러 알림 구현하기

·2026년 3월 9일

시스템 운영 중 발생하는 예외 상황을 실시간으로 파악하는 것은 매우 중요합니다. 디스코드 웹훅을 통해서 애플리케이션의 에러를 디스코드 채널로 전송하는 방법에 대한 글입니다.


1. Webhook이란?

Webhook(웹훅)은 서버에서 특정 이벤트가 발생했을 때, 다른 서버로 실시간 알림을 보내는 방식이다.

Polling과의 차이점:

  • 폴링은 클라이언트가 주기적으로 서버에 "새로운 데이터 있어?"라고 물어보는 방식
  • 웹훅은 이벤트가 발생한 시점에 서버가 클라이언트(디스코드 등)에게 데이터를 던져주는 방식. 훨씬 효율적이고 실시간성이 높다.

2. 디스코드 웹훅

(1) 알림을 받을 디스코드 채널의 [채널 편집] (톱니바퀴 아이콘)을 클릭한다.

(2) [연동] > [웹후크] 메뉴로 들어가 웹후크를 생성한다.

(3) 생성된 웹후크의 URL을 복사해 둡니다. 이 URL은 외부로 노출되지 않도록 주의해야 한다.


3. Spring Boot 구현

(1) application.yml

// application.yml
  discord:
    webhook-url: ${DISCORD_WEBHOOK_URL}

application.yml에 아까 복사한 웹훅 URL을 추가한다.


(2) DiscordMessageService

// DiscordMessageService.java
@Slf4j
@Service
public class DiscordMessageService {

    // yml에 설정한 url
    @Value("${discord.webhook-url}")
    String discordWebhookUrl;

    public void sendDiscordWebhookMessage(DiscordWebhookMessage message) {
        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add("Content-Type", "application/json; utf-8");
            
            // 전송할 메시지 객체와 헤더를 엔티티로 래핑
            HttpEntity<DiscordWebhookMessage> messageEntity = new HttpEntity<>(message, httpHeaders);

            RestTemplate template = new RestTemplate();
            ResponseEntity<String> response = template.exchange(
                    discordWebhookUrl,
                    HttpMethod.POST,
                    messageEntity,
                    String.class
            );

            // 디스코드 웹훅은 정상 전송 시 204 No Content를 반환
            if (response.getStatusCode().value() != HttpStatus.NO_CONTENT.value()) {
                log.error("[ERROR] 디스코드 메시지 전송 이후 에러 발생");
            }
        } catch (Exception e) {
            log.error("[ERROR] 디스코드 메세지 에러 ", e);
        }
    }

    public record DiscordWebhookMessage(String content) {
    }
}

메시지 전송을 담당하는 서비스로, Spring의 RestTemplate을 사용하여 디스코드 API에 POST 요청을 보낸다.


(3) BankTransferService

송금 서비스 중 인터럽트 예외가 발생했을 때 웹훅을 발송하는 예시

// BankTransferService.java
@RequiredArgsConstructor
@Service
public class BankTransferService {    
	private final DiscordMessageService discordMessageService;    
    
    @ServiceLog    
    public void transfer(SellerAccountDto sellerAccountDto, long amount) {        
    	try {            
        	Thread.sleep(100);        
        } catch (InterruptedException e) {
        	discordMessageService.sendDiscordWebhookMessage(
            	new DiscordMessageService.DiscordWebhookMessage(
                "[ERROR] BankTransferService transfer 에러 : " + sellerAccountDto)); 
			
            Thread.currentThread().interrupt();        
		}    
	}

4. 결과

코드 실행 중 예외 상황이 발생하면, 즉시 설정한 디스코드 채널로 에러 메시지가 수신되는 것을 확인할 수 있다.

  • 실시간성: 장애 발생 즉시 개발자가 인지할 수 있다.
  • 간편함: 별도의 외부 라이브러리 없이 Spring 기본 기능만으로 구현 가능하다.


0개의 댓글