프론트 에러 관측
Chrome 확장 프로그램의 Failed to fetch 걸러내기
우리 번들에서 난 것처럼 보이던 확장 프로그램 에러를 원본 스택으로 구분해 알림에서 제외했다.
프론트 에러 관측4 / 4편
목차
Slack에 TypeError: Failed to fetch 알림이 계속 들어왔다. Datadog 이슈 카드에는 우리 Next.js 청크 파일이 표시됐다. 카드만 보면 프론트 코드에서 요청을 보내다 실패한 것처럼 보였다.
같은 문구여도 실제 API 장애일 수 있고 네트워크가 끊긴 것일 수도 있어서 이름만 보고 통째로 필터링하기는 어려웠다.
Raw Stack 확인
발생량이 많은 샘플부터 원본 스택을 열어봤다. Pretty Stack에서는 우리 번들만 보였는데, 원본 스택의 첫 줄에는 chrome-extension:// 주소가 있었다.
TypeError: Failed to fetch
at window.fetch (chrome-extension://...)
at ... (/_next/static/chunks/...)

브라우저 확장 프로그램이 window.fetch를 다시 감싸고 있었다. 요청이 실패하면 확장 프로그램 코드에서 에러가 시작되고 그 아래에 실제 요청을 보낸 Next.js 청크가 이어졌다. Datadog 이슈 카드에는 아래쪽의 우리 파일이 대표 위치처럼 표시됐다.
Datadog이 처음 보여준 추천 샘플에는 우리 청크만 있었다. 같은 이슈 안에서 원본 스택에 확장 프로그램 주소가 있는 이벤트를 따로 조회하자 다른 샘플이 나왔다.
확인한 확장 프로그램은 SEO 분석 도구와 팝업 차단기, VPN, 지갑이었다. 일부는 적은 수의 세션에서 에러를 많이 남겼다. 한 세션에서는 페이지를 이동하는 동안 같은 에러가 짧은 간격으로 반복됐다. 일반적인 페이지 요청도 확장 프로그램이 감싼 window.fetch를 지나갔다.
그렇다고 모든 Failed to fetch가 확장 프로그램 때문인 건 아니었다. 확장 프로그램 주소가 없는 네트워크 실패와 API 장애는 계속 봐야 했다.
error.stack으로 거르기
처음에는 에러 파일 주소로 제외하려고 했다. 하지만 대표 파일은 우리 Next.js 청크로 잡혀 있어서 확장 프로그램 에러가 검색되지 않았다. 원본 주소가 들어 있는 건 error.stack이었다.
원본 스택에 확장 프로그램 경로가 있는 이벤트는 아래처럼 조회할 수 있다. 실제 모니터 제외 조건이 아니라 진단용 쿼리 예시다.
@error.stack:*chrome-extension*
원인을 확인한 이벤트를 기준으로 모니터의 제외 범위를 정했다. 같은 조회 구간에서 적용 전후를 비교하니 알림 후보는 줄었다.
RUM 수집 설정은 바꾸지 않고 Slack 모니터에서만 제외했다. 원본은 RUM과 Error Tracking에 그대로 남아 있다.
확장 프로그램 스택이 있다고 해서 그 세션의 모든 문제가 확장 프로그램 탓인 건 아니다. 제외 범위를 넓게 잡으면 실제 네트워크 문제도 놓칠 수 있다.
제외한 이벤트도 주기적으로 다시 보기로 했다.
같이 보이던 다른 에러
함께 반복되던 에러도 발생 위치와 세션을 확인했다. 브라우저가 내부적으로 남긴 로그인지 실제로 기능이 실패한 것인지 구분하려고 했다.
기존 필터의 문자열이 실제 메시지와 다르게 작성된 경우도 있었다. 단수·복수형 차이만으로 의도한 이벤트가 조건에 걸리지 않았다. 쿼리를 바꾼 뒤에는 실제 이벤트가 어떻게 묶이는지 다시 확인해야 했다.
Load failed도 같은 원인으로 묶을 수 없었다. Next.js <Link>의 prefetch 실패 뒤 일반 페이지 이동으로 다시 시도한 로그가 있었고, 페이지를 떠날 때 전송 중인 요청이 취소된 것으로 보이는 경우도 있었다. 나머지는 실제 리소스 실패인지 더 확인해야 했다.
Load failed는 iOS에서만 발생하는 문제가 아니라 WebKit이 요청 실패에 사용하는 문구다. Chrome은 비슷한 상황을 Failed to fetch로 남긴다. 문구만으로 원인을 정할 수 없어서 원인별 조사를 이어갔다.
애플리케이션에서 직접 던진 에러나 React hydration 에러도 원인을 더 보기 전에는 제외하지 않았다.
Datadog의 이슈 묶음도 그대로 믿을 수는 없었다. 앞에서 수정한 Server Action 구조분해 에러는 Swiper와 Firefox 주입 스크립트 에러와 같은 이슈로 묶여 있었다. 이슈 제목만 보고 라이브러리 노이즈로 Ignore했다면 실제 버그까지 같이 가려질 수 있었다. 그래서 이슈 전체를 닫는 대신 원인을 확인한 필드만 모니터 쿼리에서 제외했다.
기존 모니터에도 적용
새 모니터에서 조건을 확인한 뒤 기존 모니터도 다시 봤다. 처음에 살펴봤던 Slack 채널로 여러 원인의 스크립트 에러를 보내던 모니터였다.
이 모니터를 처음 만든 개발자에게 새 필터와 근거를 공유했다. 같은 조건을 넣어도 되는지 물었고 괜찮다는 답을 받았다. 같은 기간의 데이터로 영향 범위를 확인한 뒤 기존 모니터 쿼리에도 적용했다.
처음에는 새 모니터만 정리할 생각이었는데 며칠 동안 알림을 확인하면서 기존 모니터까지 수정하게 됐다. 지금도 새 제외 조건을 넣을 때는 원본 스택과 Session Replay를 먼저 확인하고 있다.
필터 적용 후 점검
같은 조회 구간에 제외 조건을 적용해 알림 후보가 줄었는지 비교했다. 실제 장애가 줄었는지, 중요한 에러를 빠짐없이 잡는지까지 확인한 것은 아니다.
이후 분석에서는 많이 발생하는데도 알림이 없는 이슈가 드러났다. 제외 조건 외에 이슈 상태와 모니터의 조회 범위도 봐야 했다.
같은 이슈 안에서도 이벤트마다 메시지가 다를 수 있었다. 이슈 제목에 있는 문구를 제외해도 다른 메시지의 이벤트는 조건을 통과할 수 있다.
필터를 점검할 때는 일간 리포트에는 있는데 알림에는 없는 에러도 함께 확인해야 했다.