Datadog 에러 모니터 노이즈 정리
브라우저 확장 프로그램 에러를 error.stack 기준으로 필터링했다.
Slack에 TypeError: Failed to fetch 알림이 계속 들어왔다. Datadog 이슈 카드에는 우리 Next.js 청크 파일이 표시됐다. 카드만 보면 프론트 코드에서 요청을 보내다 실패한 것처럼 보였다.
문제는 같은 이름 아래 원인이 다른 에러가 섞여 있다는 점이었다. 실제 API 장애일 수도 있고, 네트워크가 끊겼을 수도 있다. 이름만 보고 통째로 필터링할 수는 없었다.
Pretty Stack에서 안 보이던 주소가 있었다
발생량이 많은 샘플부터 원본 스택을 열어봤다. Pretty Stack에서는 우리 번들만 보였는데, 원본 스택의 첫 줄에는 chrome-extension:// 주소가 있었다.
TypeError: Failed to fetch
at window.fetch (chrome-extension://...)
at ... (/_next/static/chunks/...)

브라우저 확장 프로그램이 window.fetch를 다시 감싸고 있었다. 요청이 실패하면 확장 프로그램 코드에서 에러가 시작되고 그 아래에 실제 요청을 보낸 Next.js 청크가 이어졌다. Datadog 이슈 카드에는 아래쪽의 우리 파일이 대표 위치처럼 표시됐다.
대표 샘플만 봐도 판단이 달라졌다. Datadog이 처음 보여준 추천 샘플에는 우리 청크만 있었지만, 같은 이슈 안에서 @error.stack:*chrome-extension* 조건을 걸면 확장 프로그램이 있는 샘플이 나왔다.
확인한 확장 프로그램은 Similarweb 같은 SEO 분석 도구와 팝업 차단기, VPN, 지갑이었다. 30일 동안 chrome-extension://이 스택에 남은 에러는 2,190건이었다. Similarweb이 1,029건으로 가장 많았고, VPN 확장 프로그램에서 나온 851건은 5세션에 몰려 있었다.
Similarweb을 사용한 한 세션에서는 검색과 상품 페이지를 둘러보는 동안 같은 에러가 약 4.6초 간격으로 반복됐다. 확장 프로그램이 트래픽을 관찰하려고 window.fetch를 감싸고 있어서 특별한 조작을 하지 않아도 페이지의 요청이 모두 확장 코드를 지나갔다.
다만 모든 Failed to fetch가 같은 원인이라는 뜻은 아니었다. 확장 프로그램 주소가 없는 네트워크 실패와 API 장애는 계속 봐야 했다.
error.file 대신 error.stack을 봤다
처음에는 에러 파일 주소로 제외하려고 했다. 하지만 대표 파일은 우리 Next.js 청크로 잡혀 있어서 확장 프로그램 에러가 검색되지 않았다. 원본 주소가 들어 있는 건 error.stack이었다.
-@error.stack:*chrome-extension*
이 조건을 신규 에러 모니터에 추가했다. 수강생용 웹 운영 모니터의 30일 알림 후보는 6,086건, 37개 이슈에서 3,506건, 30개 이슈로 줄었다. 이벤트 기준으로 약 42%였다. 선생님용 웹 운영 모니터는 최근 7일 알림 이슈가 4개에서 1개로 줄었다.
여기서 줄어든 건 Datadog에 저장되는 RUM 데이터가 아니다. Slack 알림을 판단하는 모니터 대상만 줄였다. 확장 프로그램을 쓰는 사용자에게만 발생하는 네트워크 문제는 알림에서 놓칠 수 있지만, 원본은 RUM과 Error Tracking에 그대로 남겼다.
확장 프로그램 스택이 있던 세션은 전체 에러 세션의 약 0.55%와 1.24%였다. 이 사용자들에게만 발생하는 네트워크 문제는 Slack에서 놓칠 수 있다. 대신 Failed to fetch 메시지 전체를 빼지는 않았다. 확장 프로그램 주소가 없는 에러는 이전처럼 알림이 온다.
필터링한 원본도 주기적으로 다시 보기로 했다.
많이 보인다고 전부 제외하지는 않았다
같이 반복되던 노이즈도 확인했다. Firefox 내부 메시지, 저장 공간 부족, ResizeObserver, Next.js의 정상적인 redirect와 not-found 흐름은 발생 위치와 세션을 확인한 뒤 모니터 조건에 추가했다.
기존 필터가 실제 메시지와 다르게 작성된 경우도 있었다. IndexedDB 에러는 records라는 복수형으로 제외하고 있었는데 실제 메시지는 a record였다. 제외됐던 건 3건뿐이었고 94건, 89세션은 그대로 알림 대상에 남아 있었다. 바뀌지 않는 in-progress 부분을 기준으로 다시 묶었다.
반대로 Load failed는 남겨뒀다. 분석한 30일 동안 9,718건이 있었지만 같은 원인으로 묶을 수 없었다.
- 6,208건은 Next.js
<Link>의 prefetch 실패였다. 일반 페이지 이동으로 다시 시도한다는 로그였고,console에러라 신규 에러 모니터에는 원래 들어오지 않았다. - 1,606건은 페이지를 떠나는 시점에 발생했다. 전송 중이던 요청이 취소된 경우로 보였다.
- 나머지 1,872건, 743세션은 더 확인해야 할 대상으로 남겼다.
Load failed는 iOS에서만 발생하는 문제가 아니라 WebKit이 요청 실패에 사용하는 문구다. Chrome은 비슷한 상황을 Failed to fetch로 남긴다. 문구만으로 원인을 정할 수 없어서 제외하지 않았고, 8월 28일에도 105건, 49세션이 남아 있었다.
애플리케이션에서 직접 던진 에러나 React hydration 에러도 원인을 더 보기 전에는 제외하지 않았다.
Datadog의 이슈 묶음도 그대로 믿을 수는 없었다. 앞에서 수정한 Server Action 구조분해 에러는 Swiper와 Firefox 주입 스크립트 에러와 같은 이슈로 묶여 있었다. 이슈 제목만 보고 라이브러리 노이즈로 Ignore했다면 실제 버그까지 같이 가려질 수 있었다. 그래서 이슈 전체를 닫는 대신 원인을 확인한 필드만 모니터 쿼리에서 제외했다.
알림 수를 줄이는 게 목적이면 조건을 더 넓게 넣을 수 있다. 하지만 이 모니터를 만든 이유는 새 버그를 먼저 보기 위해서였다. 원인을 설명할 수 있는 항목만 뺐다.
예전에 쓰던 모니터에도 같은 조건을 넣었다
새로 만든 6개 모니터에서 조건을 확인한 뒤 예전 Slack 채널의 모니터도 다시 봤다. 처음에 모든 스크립트 에러가 쌓이던 바로 그 모니터였다.
이 모니터를 처음 만든 개발자에게 새 모니터에서 쓰고 있는 필터와 근거를 공유하고, 같은 조건을 넣어도 되는지 물었다. 같은 7일치 데이터에 필터를 적용해보면 모니터 대상 에러 이벤트가 약 94% 줄었다. 괜찮다는 답을 받고 기존 모니터 쿼리에도 적용했다.
처음에는 새 모니터만 정리할 생각이었다. 며칠 동안 알림을 직접 확인해보니 예전 모니터에도 같은 필터를 넣을 근거가 생겼다. 지금도 새 제외 조건을 넣을 때는 원본 스택과 Session Replay를 먼저 확인하고 있다.