Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sentry를 이용한 에러 추적기, React의 선언적 에러 처리

kakao
PRO
December 08, 2022

Sentry를 이용한 에러 추적기, React의 선언적 에러 처리

#React #Sentry #선언적에러처리

카카오페이 프론트엔드에서 선언적 에러처리를 통한 사용자경험과 개발자경험 증대 및 Sentry를 통한 웹뷰환경에서의 에러 추적, 장애 대응, 사용자 경험 개선기 (axios interceptor와 에러바운더리를 이용해 에러핸들링을 개선해 나가고, sentry를 통해 에러데이터를 쌓아 사용자 경험을 개선해나간 스토리로 풀어볼 예정입니다.)

발표자 : chloe.ykim
사용자 경험을 소중하게 생각하는 카카오페이 FE개발팀의 클로이, 나나입니다.

nana.na
사용자 경험을 소중하게 생각하는 카카오페이 FE개발팀의 클로이, 나나입니다.

kakao
PRO

December 08, 2022
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1. Sentryܳ ੉ਊೠ ী۞ ୶੸ӝ,
    React੄ ࢶ঱੸ ী۞ ୊ܻ
    김윤선 Chloe.ykm, 나유리 Nana.na


    카카오페이


    Copyright 2022. Kakao Corp. All rights reserved. Redistribution or public display is not permitted without written permission from Kakao.
    if(kakao)2022

    View Slide

  2. 들어가며
    기존의 에러 처리


    Error Boundaries


    라이브러리와 Error Boundaries


    선언적 에러 처리


    선언적 에러 처리의 장단점
    Sentry를 이용한 데이터 수집


    Severity 기준설정과 모니터링


    에러 데이터 분석


    개선 후, 이런 점이 좋아졌어요

    View Slide

  3. 우리가 겪어야 했던 상황들
    PM
    @FE 운영환경에서 pdf 파일 버튼 클릭 시 반응이 없어요!


    빠르게 확인 부탁드려요!
    FE
    @BE 운영환경 디버깅이 불가해서 그런데 혹시


    /v1/api/pdf 이 API응답이 어떻게 오는지 알 수 있을까요?
    BE
    @FE 해당 API 응답을 확인해보니 빈 배열로 내려가는


    경우가 있는 것 같습니다.

    View Slide

  4. 우리가 겪어야 했던 상황들
    FE
    @BE 운영환경 디버깅이 불가해서 그런데 혹시


    /v1/api/pdf 이 API응답이 어떻게 오는지 알 수 있을까요?
    BE
    @FE 해당 API 응답을 확인해보니 빈 배열로 내려가는


    경우가 있는 것 같습니다.
    PM
    @FE 운영환경에서 pdf 파일 버튼 클릭 시 반응이 없어요!


    빠르게 확인 부탁드려요!

    View Slide

  5. 우리가 겪어야 했던 상황들
    FE
    @BE 운영환경 디버깅이 불가해서 그런데 혹시


    /v1/api/pdf 이 API응답이 어떻게 오는지 알 수 있을까요?
    BE
    @FE 해당 API 응답을 확인해보니 빈 배열로 내려가는


    경우가 있는 것 같습니다.
    PM
    @FE 운영환경에서 pdf 파일 버튼 클릭 시 반응이 없어요!


    빠르게 확인 부탁드려요!

    View Slide

  6. PM
    @FE 운영환경에서 pdf 파일 버튼 클릭 시 반응이 없어요!


    빠르게 확인 부탁드려요!
    우리가 겪어야 했던 상황들
    FE
    @BE 운영환경 디버깅이 불가해서 그런데 혹시


    /v1/api/pdf 이 API응답이 어떻게 오는지 알 수 있을까요?
    BE
    @FE 해당 API 응답을 확인해보니 빈 배열로 내려가는


    경우가 있는 것 같습니다.
    이슈 감지, 원인 파악, 해결까지 약 4시간 소요

    View Slide

  7. PART1. 에러 추적을 개선해보자!

    View Slide

  8. Frontend에서의 에러
    데이터 영역에서의 에러 화면 영역에서의 에러
    런타임 에러
    외부요인에 의한 에러

    View Slide

  9. 에러 데이터


    쌓기
    Severity


    기준설정 및


    모니터링
    에러 데이터

    분석
    분석 결과에


    따른 개선
    에러 추적을 개선해보자!

    View Slide

  10. 에러 데이터


    쌓기
    Severity


    기준설정 및


    모니터링
    에러 데이터

    분석
    분석 결과에


    따른 개선
    에러 추적을 개선해보자!

    View Slide

  11. Sentry는 실시간 로그 취합 및 분석 도구이자


    모니터링 플랫폼입니다.
    Sentry
    로그에 대한 다양한 정보를 제공하고 시각화 도구를


    통해 발생한 이벤트들을 쉽게 분석할 수 있도록 도와줍니다.
    다양한 플랫폼을 지원합니다.

    View Slide

  12. 에러 데이터 쌓기
    captureException과 captureMessage 두 가지 API를 이용하여 에러 데이터를 전송할 수 있습니다.
    import * as Sentry from '@sentry/react';


    try {


    fetchAccountInfoApi();


    } catch (error) {


    Sentry.captureException(error);


    }
    captureException로 에러 데이터 전송
    import * as Sentry from '@sentry/react';


    Sentry.captureMessage(‘API ࢲߡ ী۞о ߊࢤೞ৓णפ׮!');


    captureMessage로 에러 데이터 전송

    View Slide

  13. 에러 데이터 쌓기
    captureException과 captureMessage 두 가지 API를 이용하여 에러 데이터를 전송할 수 있습니다.
    import * as Sentry from '@sentry/react';


    try {


    fetchAccountInfoApi();


    } catch (error) {


    Sentry.captureException(error);


    }
    captureException로 에러 데이터 전송
    import * as Sentry from '@sentry/react';


    Sentry.captureMessage(‘API ࢲߡ ী۞о ߊࢤೞ৓णפ׮!');


    captureMessage로 에러 데이터 전송
    에러 데이터는 쌓았는데 검색도 어렵고, 구분하기도 어렵고…

    View Slide

  14. Scopes
    Add Context Breadcrumbs
    Transaction Name
    Customized Tags
    Issue Grouping Level

    View Slide

  15. Scopes
    Add Context Breadcrumbs
    Transaction Name
    Customized Tags
    Issue Grouping Level

    View Slide

  16. import * as Sentry from '@sentry/react';


    Sentry.withScope((scope) => {


    scope.setTag('type', 'api');


    scope.setLevel(Sentry.Severity.Error);


    Sentry.captureException(


    new Error('API Internal Server Error'));


    });
    withScope로 해당 에러의 상세정보 전송
    import * as Sentry from '@sentry/react';


    Sentry.configureScope((scope) => {


    scope.setUser({


    accountId: 2022,


    email: '[email protected]',


    });


    scope.setTag({


    webviewType: 'WEB'


    });


    });


    con
    fi
    gureScope로 사용자 정보 전송
    에러 데이터 풍부하게 쌓기 - Scope
    con
    fi
    gureScope로는 공통 정보를 withScope로는 각 에러 상황 시 추가 정보를 전송합니다.

    View Slide

  17. 에러 데이터 풍부하게 쌓기 - Context
    이벤트에 임의의 데이터를 연결할 수 있는 context를 이용해 추가 정보를 전송합니다.


    검색은 할 수 없고 해당 이벤트가 발생한 이벤트 로그에서 확인할 수 있습니다.
    // axios੄ errorё୓


    const { method, url, params, data, headers } = error.config;


    const { data, status } = error.response;


    Sentry.setContext('API Request Detail', {


    method,


    url,


    params,


    data,


    headers,


    });


    Sentry.setContext('API Response Detail', {


    status,


    data,


    });

    View Slide

  18. import * as Sentry from '@sentry/react';


    // withScopeܳ ੉ਊೞৈ ౠ੿ ੉߮౟ী tagܳ ࢸ੿


    Sentry.withScope((scope) => {


    scope.setTag('type', 'api');


    scope.setTag('api', 'general');


    scope.setLevel(Sentry.Severity.Warning);


    Sentry.captureException(new Error('API Internal Server Error’));


    });
    에러 데이터 풍부하게 쌓기 - Customized Tags
    tag는 키와 값이 쌍으로 이루어진 문자열입니다.


    tag는 인덱싱이 되는 요소이기 때문에 이슈 검색 및 트래킹을 신속하게 진행할 수 있습니다.

    View Slide

  19. 에러 데이터 풍부하게 쌓기 - Level
    이벤트마다 level을 설정하여 이벤트의 중요도를 식별할 수 있습니다.


    fetal, error, warning, log, info, debug, critical로 severity를 설정할 수 있습니다.
    import * as Sentry from '@sentry/react';

    Sentry.withScope((scope) => {


    scope.setTag('type', 'api');


    scope.setTag('api', 'general');


    scope.setLevel(Sentry.Severity.Error); // error level۽ ࢸ੿


    Sentry.captureException(new Error('API Internal Server Error’));


    });
    Sentry.withScope((scope) => {


    scope.setTag('type', 'api');


    scope.setTag('api', 'timeout');


    scope.setLevel(Sentry.Severity.Warning); // warning level۽ ࢸ੿


    Sentry.captureException(new ApiError('API Timeout Error’));


    });

    View Slide

  20. 에러 데이터 풍부하게 쌓기 - Issue Grouping
    모든 이벤트는
    fi
    ngerprint를 가지고 있습니다.


    fi
    ngerprint가 동일한 이벤트는 하나의 이슈로 그룹화되며 재설정 할 수 있습니다.
    import * as Sentry from '@sentry/react';


    // axios੄ errorё୓


    const { method, url } = error.config;


    const { status } = error.response;


    // withScopeܳ ੉ਊೞৈ fingerprintܳ ੤ࢸ੿


    Sentry.withScope((scope) => {


    scope.setTag(‘type', 'api');


    scope.setTag(‘api’, 'general');


    scope.setFingerprint([method, status, url]);


    Sentry.captureException(new Error('API Internal Server Error’));


    });
    같은 API에 대한 에러가


    fi
    ngerprint 설정에 의해 grouping

    View Slide

  21. 에러 데이터


    쌓기
    Severity


    기준설정 및


    모니터링
    에러 데이터

    분석
    분석 결과에


    따른 개선
    에러 추적을 개선해보자!

    View Slide

  22. 알람 조건 설정하기
    처음 보는 이슈가 생길 경우


    해결된 이슈가 다시 발생할 경우


    무시하고 있던 이슈가 해제될 경우
    이벤트의 Level이 조건에 맞는 경우


    이벤트의 Attribute가 조건에 맞는 경우


    이벤트의 Tag가 조건에 맞는 경우


    이슈가 N번 중복 발생할 경우


    원하는 레벨의 이벤트가 N번 발생할 경우
    slack


    kakaowork


    jira
    When If Then

    View Slide

  23. 알람 조건 설정하기
    처음 보는 이슈가 생길 경우


    해결된 이슈가 다시 발생할 경우


    무시하고 있던 이슈가 해제될 경우
    이벤트의 Level이 조건에 맞는 경우


    이벤트의 Attribute가 조건에 맞는 경우


    이벤트의 Tag가 조건에 맞는 경우


    이슈가 N번 중복 발생할 경우


    원하는 레벨의 이벤트가 N번 발생할 경우
    When If Then
    slack


    kakaowork


    jira

    View Slide

  24. 알람 조건 설정하기

    View Slide

  25. 에러 데이터


    쌓기
    Severity


    기준 설정 및


    모니터링
    에러 데이터

    분석
    분석 결과에


    따른 개선
    에러 추적을 개선해보자!

    View Slide

  26. 에러 데이터 수집 전 세웠던 가설
    QA 과정을 거치기 때문에


    화면 영역에서


    발생하는 에러는


    많지 않을 것이다.
    가설1
    데이터 영역에서


    발생하는 API에 대한


    에러가 대부분일 것이다.
    가설2
    특정 기기나 브라우저


    에서 발생하는


    에러가 있을 것이다.


    (크로스 브라우징 이슈)
    가설3

    View Slide

  27. 수집한 에러 데이터 분석
    ApiNotFoundError
    2%
    2%
    2%
    7%
    12%
    28%
    47% ApiNotFoundError
    TypeError
    ReferenceError
    카카오페이 펀드 서비스 에러 데이터 분석
    ApiInternalServerError
    ApiTimeoutError
    ChunkLoadError

    View Slide

  28. 에러 데이터


    쌓기
    Severity


    기준설정 및


    모니터링
    에러 데이터

    분석
    분석 결과에


    따른 개선
    에러 추적을 개선해보자!

    View Slide

  29. 유의미한 데이터를 수집하자
    chunk load 에러나


    network 에러는


    수집 제외


    (timeout 에러는 수집)
    분석하고자 하는


    API의 http status를


    구분하여 수집


    (4xx 에러는 부분적 수집 제외)
    에러 데이터뿐만 아니라


    디버깅과 분석에 필요한


    추가적인 정보 수집

    View Slide

  30. 유의미한 데이터를 수집하자
    tag, level 등의 기능을 이용해


    디버깅에 필요한 정보성 데이터 수집

    View Slide

  31. 서버와의 로그 분석 정합성 높이기
    서버와 약속된 custom header를 추가하여 API를 요청합니다.


    이는 에러 상황 시 서버 로그와 프론트엔드에 남은 데이터를 서로 대조하여 분석의 정합성을 높일 수 있습니다.
    custom header를 추가하여


    api를 요청한 서버 로그
    검색이 되는 요소인 tag를 이용하여


    custom header를 수집

    View Slide

  32. 에러 추적 개선 후, 이런 점이 좋아졌어요!

    View Slide

  33. 에러 추적 개선 후, 이런 점이 좋아졌어요
    브라우저 버전 문제나 빌드 설정과 같은 문제로 발생한


    예상하지 못 했던 에러들을 발견하여 사용자 경험을


    개선시킬 수 있었습니다.


    장애 탐지 시간, 원인 파악, 해결까지의 시간이 줄었습니다.


    CS 인입 시 사용자의 환경에서 재현하지 않아도 에러 원인을


    파악하고 이전보다 정확하게 안내할 수 있게 되었습니다.


    개발자 경험이 좋아졌습니다.
    import 'core-js/features/object/entries';


    import 'core-js/features/object/values';
    사용자의 웹뷰 브라우저 버전을 확인하고
    대응하기 위하여 poly
    fi
    ll 추가

    View Slide

  34. 에러 추적 개선 후, 이런 점이 좋아졌어요
    브라우저 버전 문제나 빌드 설정과 같은 문제로 발생한


    예상하지 못 했던 에러들을 발견하여 사용자 경험을


    개선시킬 수 있었습니다.


    장애 탐지 시간, 원인 파악, 해결까지의 시간이 줄었습니다.


    CS 인입 시 사용자의 환경에서 재현하지 않아도 에러 원인을


    파악하고 이전보다 정확하게 안내할 수 있게 되었습니다.


    개발자 경험이 좋아졌습니다.
    설정한 threshold 및 알람 조건 기준에


    따라 알람 메시지를 통해 이슈 또는 장애 파악

    View Slide

  35. 에러 추적 개선 후, 이런 점이 좋아졌어요
    브라우저 버전 문제나 빌드 설정과 같은 문제로 발생한


    예상하지 못 했던 에러들을 발견하여 사용자 경험을


    개선시킬 수 있었습니다.


    장애 탐지 시간, 원인 파악, 해결까지의 시간이 줄었습니다.


    CS 인입 시 사용자의 환경에서 재현하지 않아도 에러 원인을


    파악하고 이전보다 정확하게 안내할 수 있게 되었습니다.


    개발자 경험이 좋아졌습니다.
    CS

    담당자
    안드로이드 XXX 버전에서 해당


    서비스에 접속이 안된다는 CS가


    인입되었습니다. 확인 부탁드립니다.
    안드로이드 XXX 버전에서 사용하는


    웹 브라우저 버전에서 해당 서비스를


    지원하지 못하는 현상이 있습니다.


    브라우저 업데이트로 안내부탁드리며,

    해당 이슈는 빠르게 수정하겠습니다.
    FE

    View Slide

  36. 에러 추적 개선 후, 이런 점이 좋아졌어요
    브라우저 버전 문제나 빌드 설정과 같은 문제로 발생한


    예상하지 못 했던 에러들을 발견하여 사용자 경험을


    개선시킬 수 있었습니다.


    장애 탐지 시간, 원인 파악, 해결까지의 시간이 줄었습니다.


    CS 인입 시 사용자의 환경에서 재현하지 않아도 에러 원인을


    파악하고 이전보다 정확하게 안내할 수 있게 되었습니다.


    개발자 경험이 좋아졌습니다.

    View Slide

  37. PART2. 에러 처리를 개선해보자!

    View Slide

  38. 사용자 경험을 어렵게 만드는 기존의 에러 처리
    하나의 api에서 에러가


    발생해도 에러 페이지로 이동

    View Slide

  39. 에러/예외 케이스 화면들
    일반적인 에러 네트워크 에러 강제 업데이트 서비스 점검

    View Slide

  40. axios interceptor
    기존의 에러 처리는


    axios interceptor의


    reject callback으로 처리했습니다.
    axios.interceptors.response.use(_, onResponseRejected);


    function onResponseRejected(error: Error) {


    return new Promise((_, reject) => {


    /** ઺ۚ */


    if (checkIsAxiosNetworkError(error)) {


    setTimeout(() => handleNetworkError(error, reject), 200);


    return;


    }


    if (checkIsAxiosTimeoutError(error)) {


    return handleTimeoutError(error, reject);


    }


    const errorCode = error.response?.data?.errorCode;


    const status = error.response?.status;


    if (errorCode) {


    switch (errorCode) {


    case KPAY_COMMON_ERROR_CODES.҅੿੉࢚:


    return handleKickOutError(error);


    /** ઺ۚ */


    }


    }


    });


    }


    네트워크 에러 체크
    타임아웃 에러 체크
    계정이상 에러 체크

    View Slide

  41. axios interceptor
    기존의 에러 처리는


    axios interceptor의


    reject callback으로 처리했습니다.
    axios.interceptors.response.use(_, onResponseRejected);


    function onResponseRejected(error: Error) {


    return new Promise((_, reject) => {


    /** ઺ۚ */


    if (checkIsAxiosNetworkError(error)) {


    setTimeout(() => handleNetworkError(error, reject), 200);


    return;


    }


    if (checkIsAxiosTimeoutError(error)) {


    return handleTimeoutError(error, reject);


    }


    const errorCode = error.response?.data?.errorCode;


    const status = error.response?.status;


    if (errorCode) {


    switch (errorCode) {


    case KPAY_COMMON_ERROR_CODES.҅੿੉࢚:


    return handleKickOutError(error);


    /** ઺ۚ */


    }


    }


    });


    }


    네트워크 에러 체크
    타임아웃 에러 체크
    계정이상 에러 체크
    axios interceptor에서 예외 케이스는 어떻게 처리하지?


    전역에서 처리하는 흐름이 과연 맞을까?

    View Slide

  42. axios interceptor, 이런 점이 불편했어요
    에러 화면을 보여주려면 라우트 이동으로


    처리해야만 하는 불편함이 있었습니다.
    history.push(‘/error’);

    View Slide

  43. axios interceptor, 이런 점이 불편했어요
    전역 에러를 처리하는 것은 수월하나


    화면의 일부만 에러 상태로 대응하는 것은 어렵습니다.
    부분적 에러 처리

    View Slide

  44. Error Boundaries

    View Slide

  45. ErrorBoundaries
    React 16에서 도입된


    에러 경계 (error boundaries)를 활용하여


    하위 컴포넌트 트리의 자바스크립트 에러를 포착하고


    Fallback UI를 보여줄 수 있습니다.


    에러 바운더리를 통해 선언적 에러 처리가 가능합니다.

    View Slide

  46. 명령형 프로그래밍 선언형 프로그래밍
    HOW What

    View Slide

  47. 명령형 에러 처리 선언형 에러 처리
    const ComponentWithPossiblyError = () => {


    const { error: err1 } = useSomeQuery();


    const { error: err2 } = useAnotherQuery();


    if (err1 || err2) {


    return ;


    }


    return ;


    };
    const ComponentWithPossiblyError = () => {


    return (











    );


    };
    Error Boundaries

    View Slide

  48. ErrorBoundaries의 구조
    class ErrorBoundary extends React.Component {


    constructor(props) {


    super(props);


    this.state = { hasError: false };


    }


    static getDerivedStateFromError(error) {


    return { hasError: true };


    }


    componentDidCatch(error, errorInfo) {


    logException(error, errorInfo);


    }


    render() {


    if (this.state.hasError) {


    return Something went wrong.;


    }


    return this.props.children;


    }


    }


    다음 렌더링에서 fallback UI가


    보이도록 상태 업데이트
    에러 리포팅 서비스에 에러 기록
    커스텀한 fallback UI 렌더링

    View Slide

  49. react
    -
    error
    -
    boundary
    Error Boundaries의 Fallback Component를 직관적으로 작성할 수 있도록 도와주는 라이브러리입니다.
    import { ReactErrorBoundary } from 'react-error-boundary';


    const FallbackComponent = () => {


    return (


    ী۞ಕ੉૑


    );


    }


    export const App = () => {


    return (


    }>





    {/* ઺ۚ */}








    )


    }


    서비스 성격이나 에러 상황에 적절한


    fallback component 구현 가능

    View Slide

  50. react
    -
    query와 Error Boundaries
    React의 Error Boundaries는 본래


    이벤트 핸들러의 에러를 포착하지 않습니다.


    react
    -
    query에서는


    useErrorBoundary 옵션을 제공하여,


    API에서 에러가 발생하면 이를


    Error Boundaries가 캐치할 수 있습니다.
    • useErrorBoundary: undefined | boolean | (error: TError,
    query: Query) => boolean


    ◦ Defaults to the global query config's
    useErrorBoundary value, which is undefined


    ◦ Set this to true if you want errors to be thrown in
    the render phase and propagate to the nearest error
    boundary


    ◦ Set this to false to disable suspense's default
    behavior of throwing errors to the error boundary.


    ◦ If set to a function, it will be passed the error and
    the query, and it should return a boolean indicating
    whether to show the error in an error boundary (true)
    or return the error as state (false)

    View Slide

  51. 선언적 에러 처리를 적용해보자!
    Error

    Boundaries의

    관심사 분리
    axios

    interceptor

    코드 줄이기
    Error

    Boundaries 및

    Fallback


    Component 작성

    View Slide

  52. axios

    interceptor

    코드 줄이기
    Error

    Boundaries의

    관심사 분리
    Error

    Boundaries 및

    Fallback


    Component 작성
    선언적 에러 처리를 적용해보자!

    View Slide

  53. if (isNetworkError(error)) {


    setTimeout(() =>


    handleNetworkError(error, reject)


    , 200);


    return;


    }


    if (isTimeoutError(error)) {


    return handleTimeoutError(error, reject);


    }


    const errorCode = error.response?.data?.errorCode;


    const status = error.response?.status;


    if (errorCode) {


    /** ઺ۚ */
    axios interceptor에서 처리하는 코드 줄이기
    기존 axios interceptor

    View Slide

  54. if (isNetworkError(error)) {


    setTimeout(() =>


    handleNetworkError(error, reject)


    , 200);


    return;


    }


    if (isTimeoutError(error)) {


    return handleTimeoutError(error, reject);


    }


    const errorCode = error.response?.data?.errorCode;


    const status = error.response?.status;


    if (errorCode) {


    /** ઺ۚ */
    axios interceptor에서 처리하는 코드 줄이기
    기존 axios interceptor
    if (isAxiosError(error) && isNetworkError(error)) {


    setTimeout(() => reject(error), 200);


    } else {


    reject(error);


    }


    변경한 axios interceptor

    View Slide

  55. axios

    interceptor

    코드 줄이기
    Error

    Boundaries의

    관심사 분리
    선언적 에러 처리를 적용해보자!
    Error

    Boundaries 및

    Fallback


    Component 작성

    View Slide

  56. Error Boundaries의 관심사 분리
    Error Boundaries를 관심사별로 분리하기 위해 중첩으로 구성하였습니다.
    import { Outlet } from 'react-router-dom';


    import { ApiErrorBoundary, RootErrorBoundary } from '~/shared/components';


    export const AppLayout = () => {


    return (

















    );


    };


    그 외 Frontend Error
    api에서 발생하는 Error

    View Slide

  57. axios

    interceptor

    코드 줄이기
    Error

    Boundaries의

    관심사 분리
    Error

    Boundaries 및

    Fallback


    Component 작성
    선언적 에러 처리를 적용해보자!

    View Slide

  58. const ApiErrorBoundary = ({ children }) => {


    const { reset } = useQueryErrorResetBoundary();


    const { key } = useLocation();


    return (




    FallbackComponent={FallbackComponent}


    onReset={reset}


    resetKeys={[key]}


    >


    {children}





    );


    };


    Fallback Component 작성
    API 에러를 처리하는 Error Boundaries (Root Level)
    react
    -
    query에서 query를 reset하는


    custom hook
    location 객체의 key를 기반으로 reset


    트리거

    View Slide

  59. Fallback Component 작성
    function FallbackComponent({ error, resetErrorBoundary }) {


    useEffect(() => {


    captureApiError(props.error);


    }, []);


    if (!isAxiosError(error)) {


    throw error;


    }


    /** ઺ۚ */


    // 500 Error & ӝఋ ੌ߈ Api Error


    return (




    resetErrorBoundary={resetErrorBoundary}


    />;


    );


    };
    상위 Error Boundaries인


    Global Error Boundaries로 에러 위임
    API Error Boundaries의 Fallback Component
    Sentry와 같은 에러 모니터링 서비스에


    에러 데이터 전송 가능

    View Slide

  60. const ProductList = () => {


    return (


    <>





























    >


    );


    };
    Local (Block) Error Boundaries
    Local Error Boundaries가 적용된 컴포넌트

    View Slide

  61. const ProductList = () => {


    return (


    <>





























    >


    );


    };
    Local (Block) Error Boundaries
    Local Error Boundaries가 적용된 컴포넌트

    View Slide

  62. Local (Block) Error Boundaries
    const FallbackComponent = (props) => {


    if (isApiRequiredError(props.error)) {


    throw props.error;


    } else {


    return ;


    }


    };


    const LocalApiErrorBoundary = ({ children }) => {


    return (





    {children}





    );


    };
    Local Error Boundaries와 Fallback Component
    공통 에러 처리가 필요한 에러들은 상위로


    위임

    View Slide

  63. 공통 에러 처리가 필요한 경우
    iOS에서 unload event가 발생하면 axios에서 호출 중이던 API에서 Network Error가 발생합니다.


    이때 발생한 에러는 Error Boundaries가 포착하면 안 됩니다.
    function onResponseRejected(error: Error) {


    return new Promise((_resolve, reject) => {


    if (checkIsAxiosError(error) && checkIsNetworkError(error)) {


    setTimeout(() => reject(error), 200);


    } else {


    reject(error);


    }


    });


    }
    iOS의 location 이동으로 인한


    Network Error 방지를 위해 지연시킴

    View Slide

  64. 에러 처리 개선 후, 이런 점이 좋아졌어요!

    View Slide

  65. 에러 처리 개선 후, 이런 점이 좋아졌어요
    비즈니스 로직에 집중한 에러 처리가 가능합니다.


    UI 일부에서 발생하는 에러를 전역으로


    전파시키지 않고 처리할 수 있습니다.
    const ComponentWithPossiblyError = () => {


    const { error: err1 } = useSomeQuery();


    const { error: err2 } = useAnotherQuery();


    if (err1 || err2) {


    return ;


    }


    return ;


    };
    명령형


    에러 처리

    View Slide

  66. 에러 처리 개선 후, 이런 점이 좋아졌어요
    비즈니스 로직에 집중한 에러 처리가 가능합니다.


    UI 일부에서 발생하는 에러를 전역으로


    전파시키지 않고 처리할 수 있습니다.
    const ComponentWithPossiblyError = () => {


    const { error: err1 } = useSomeQuery();


    const { error: err2 } = useAnotherQuery();


    if (err1 || err2) {


    return ;


    }


    return ;


    };
    명령형


    에러 처리
    const ComponentWithPossiblyError = () => {


    return (











    );


    };
    선언형


    에러 처리

    View Slide

  67. 에러 처리 개선 후, 이런 점이 좋아졌어요
    비즈니스 로직에 집중한 에러 처리가 가능합니다.


    UI 일부에서 발생하는 에러를 전역으로


    전파시키지 않고 처리할 수 있습니다.
    const Parent = () => {


    return (











    );


    };


    const ComponentWithPossiblyError = () => {


    const { data } = useSomeQuery({


    useErrorBoundary: true,


    });


    return ;


    };
    이 컴포넌트 상위로

    에러가 전파되지 않음

    View Slide

  68. 선언적 에러 처리를 고민해야 하는 부분도 존재합니다
    전역에서 처리되어야 하는 에러를 구분해야 합니다.
    export function FallbackComponent({ error, resetErrorBoundary }) {


    if (!isAxiosError(error)) {


    throw error;


    }


    // ઺ۚ...


    };


    export function FallbackComponent({ error, resetErrorBoundary }) {


    if (!isAxiosError(error)) {


    return ;


    }


    if (isRootApiError(error)) {


    throw error;


    }


    // ઺ۚ...


    };
    PayAxiosError가 아니라면 상위


    Error Boundaries로 위임
    ApiErrorBoundary에서 처리해야


    하는 에러라면 위임

    View Slide

  69. Wrap
    -
    up

    View Slide

  70. Wrap
    -
    up
    데이터 영역에서의 에러
    화면 영역에서의 에러
    외부요인에 의한 에러
    런타임에 의한 에러
    Scopes
    Add Context
    Breadcurmbs
    Transaction Name
    Customized Tags
    Issue Grouping
    Level
    에러 데이터 분석
    모니터링
    사용자와 개발자


    경험 향상

    View Slide

  71. Wrap
    -
    up
    react
    -
    error
    -
    boundary
    Block Error Boundaries
    Error Boundaries
    Fallback Component
    선언적 에러 처리
    중첩 Error Boundaries

    View Slide

  72. Wrap
    -
    up
    선언적 에러처리 사용자와 개발자


    경험 향상
    견고한 서비스를


    제공하는데 도움

    View Slide

  73. E.O.D

    View Slide