개발 slecs

Discord에서 시간별 누적 통계 대시보드 구현

목차

시간별 누적 통계를 한눈에 추적할 수 있는 대시보드를 만들었다. Discord의 메시지 편집 기능을 활용해서 기존 메시지를 계속 업데이트하는 방식으로 구현했는데, 이게 생각보다 효과적인 패턴이었다.

왜 이 작업이 필요했나

통계 데이터를 모니터링할 때 매번 새로운 메시지를 보내는 방식은 몇 가지 문제가 있다. 먼저 채널이 금세 메시지로 지저분해진다. 시간마다 통계를 보낸다면 몇 시간 지나면 같은 정보의 메시지가 수십 개 쌓인다. 두 번째는 최신 데이터를 찾기 어렵다는 것. 사용자가 가장 최근 통계를 보려면 맨 위로 스크롤해야 한다. 세 번째는 채널 내용이 혼란스러워진다는 것. 통계 메시지와 다른 운영 메시지가 섞여 있으면 중요한 공지를 놓치기 쉽다.

그래서 "기존 메시지를 계속 편집하는" 방식을 선택했다. 대시보드 메시지는 항상 같은 위치에 있고, 데이터만 업데이트된다. 마치 웹 대시보드처럼 동적으로 값이 변하는 경험을 Discord에서 그대로 구현할 수 있다.

Discord EDIT 패턴이 뭔가

Discord API는 메시지 생성 후에 그 메시지를 편집할 수 있는 기능을 제공한다. 우리는 이를 활용해서:

  1. 첫 실행 때 초기 통계 메시지를 하나 생성한다
  2. 이후 주기적으로 (매 시간 또는 정해진 간격으로) 그 메시지의 내용을 새 데이터로 갱신한다
  3. 채널에 새 메시지가 쌓이지 않으므로 채널은 깔끔하게 유지된다
# 의사 코드로 표현하면:
def update_stats_dashboard():
    latest_stats = fetch_hourly_stats()  # 시간별 누적 데이터 조회
    formatted_message = format_stats(latest_stats)

    if message_id_exists():
        edit_message(message_id, formatted_message)  # 기존 메시지 편집
    else:
        create_new_message(formatted_message)  # 첫 번째 생성
        store_message_id()  # 다음을 위해 ID 저장

이 패턴의 장점:

  • 채널 깔끔함: 같은 메시지가 계속 갱신되므로 메시지 개수가 늘어나지 않음
  • 최신 정보 우선: 가장 중요한 통계가 항상 눈에 띄는 위치에 있음
  • 데이터 추적: 편집 이력이 남아서 (Discord 메시지 수정 기록) 언제 어떤 값으로 변했는지 추적 가능
  • API 효율: 새 메시지를 계속 보내는 것보다 편집 요청이 상대적으로 가벼울 수 있음

시간별 누적 통계의 의미

이 대시보드는 "시간별 누적(cumulative)" 데이터를 보여준다는 게 중요한 포인트다.

구분 설명 예시
시간별 데이터를 1시간 단위로 집계 14:00~15:00, 15:00~16:00, ...
누적(cumulative) 이전 시간부터의 합계를 보여줌 1시간차: 100건, 2시간차: 250건(100+150), 3시간차: 400건(250+150)

누적 통계는 "어느 정도 진행됐는가"를 한눈에 보여주는 데 효과적하다. 일반적으로 실시간 처리량을 모니터링하는 경우, 일일 목표에 대한 진행도를 추적하는 경우, SLA 달성도를 확인하는 경우 등에서 많이 사용된다.

구현 과정에서 배운 점들

scripts/stats-dashboard.py 는 이런 로직을 담당한다:

  • Discord 메시지 ID를 어디에 저장할 것인가? (파일? DB? 환경변수?)
  • 통계 조회는 얼마나 자주 할 것인가? (매시간? 30분마다?)
  • 통계 데이터 포맷은 어떻게 보기 좋게 표현할 것인가? (테이블? 그래프 이모지?)
  • 메시지 편집 실패 시 (권한 부족, 메시지 삭제됨, API 오류) 어떻게 대응할 것인가?

특히 마지막 부분이 중요했다. EDIT 패턴은 메시지가 계속 같아야 한다는 가정 위에서 동작하는데, 만약 누군가 그 메시지를 실수로 삭제하면? 또는 봇의 권한이 취소되면? 이런 엣지 케이스를 처리하지 않으면 대시보드가 조용히 작동을 멈춘다.

그래서 일반적으로는 graceful fallback을 구현한다:

try:
    edit_message(message_id, new_content)
except (NotFound, Forbidden):
    # 메시지가 없거나 편집 권한이 없음
    new_message = create_new_message(new_content)
    update_stored_message_id(new_message.id)

이런 식으로 예상치 못한 상황에서도 대시보드가 자동으로 복구된다.

팀 입장에서의 영향

개별 개발자 입장에서는 "또 다른 대시보드"일 수 있지만, 운영 관점에서는 꽤 유용하다. 운영자가 자주 보는 채팅 플랫폼에서 바로 통계를 확인할 수 있고, 별도 웹 대시보드 창을 열지 않아도 된다. 몇 초씩의 단축이지만, 이런 작은 개선이 반복되면 하루 누적으로는 꽤 의미 있는 시간 절약이 된다. 또한 이상 상황을 빠르게 캐치할 수 있다. 누적 통계가 정체되면 시스템에 문제가 있다는 신호니까.

비슷한 패턴을 다른 모니터링 케이스에도 적용할 수 있다. 배포 상태, 크롤링 진행도, 에러 로그 요약 등도 같은 방식으로 구현할 수 있다는 뜻이다. 앞으로는 이 패턴을 좀 더 일반화해서 "메시지 ID 자동 관리", "포맷팅 템플릿" 같은 재사용 가능한 모듈로 만들어 두면 비슷한 요청이 들어올 때 빠르게 대응할 수 있을 것 같다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.