• EnglishEspañol日本語한국어Português
  • 로그인지금 시작하기

이 한글 문서는 사용자의 편의를 위해 기계 번역되었습니다.

영문본과 번역본이 일치하지 않는 경우 영문본이 우선합니다. 보다 자세한 내용은 이 페이지를 방문하시기 바랍니다.

문제 신고

랩 파트 3: 애플리케이션의 오류 디버그

이 절차는 New Relic 브라우저로 웹 앱의 문제를 해결하는 방법을 알려주는 랩의 일부입니다.

랩의 각 절차는 마지막 절차를 기반으로 하므로 이 절차를 시작하기 전에 마지막 절차인 브라우저 에이전트로 애플리케이션 계측을완료했는지 확인하십시오.

지금까지 애플리케이션이 제대로 작동했습니다. 사용자가 주문할 수 있었고 귀하의 서비스에 만족했습니다. 그러나 이제 애플리케이션에 약간의 통찰력이 있으므로 일부 JavaScript 오류가 표시되고 있음을 알 수 있습니다.

이 절차에서는 New Relic 브라우저를 사용하여 이러한 오류의 원인을 찾고 적시에 애플리케이션을 디버깅합니다.

중요

New Relic에서 데이터를 보려면 다음을 활성화해야 합니다. 이 절차를 위해.

아직 하지 않았다면 브라우저 에이전트로 앱을 계측하십시오.

프런트엔드 오류 디버그

안타까운 소식은 애플리케이션에 몇 가지 오류가 있음을 확인했다는 것입니다. 좋은 소식은 최근에 브라우저 에이전트로 애플리케이션을 계측했다는 것입니다! 아직 로그인하지 않은 경우 New Relic으로 이동하여 계정에 로그인합니다.

New Relic 홈페이지에서 Browser 로 이동하여 Relicstaurants 애플리케이션을 선택합니다.

여기에서 Page views with JavaScript errors[JavaScript 오류가 있는 페이지 보기], Core web vitals[핵심 웹 바이탈], User time on the site[사이트의 사용자 시간], Initial page load and route changes[초기 페이지 로드 및 경로 변경]등을 포함하여 브라우저 애플리케이션과 관련된 모든 데이터를 볼 수 있습니다.

데이터가 보이지 않습니까? 브라우저 모니터링을 활성화했고 부하 생성기가 실행 중인지 확인하십시오.

Page views with javascript errors[자바스크립트 오류가 있는 공지 페이지 ] 보기.

여기에서 애플리케이션에 일부 Javascript 오류가 있음을 나타내는 스파이크가 표시됩니다.

Page views with javascript errors[자바스크립트 오류가 있는 페이지 보기를] 클릭합니다.

총 오류 인스턴스와 함께 모든 JS 오류를 볼 수 있는 JS errors[JS 오류] 페이지로 이동합니다.

자세한 내용을 보려면 Cart cannot be empty 오류를 클릭하십시오.

여기에서 errorMessage, INSTANCES, INTERACTIONS AFFECTED 및 오류와 관련된 기타 세부 정보를 볼 수 있습니다.

그런 다음 Error Instances[오류 인스턴스] 탭으로 이동합니다.

여기에서 Event Log[이벤트 로그], Stack trace[스택 추적] 및 기타를 포함하여 특정 오류와 관련된 자세한 내용을 볼 수 있습니다.

Error Instances[오류 인스턴스] 페이지에서 아래로 스크롤하여 Stack trace[스택 추적을]봅니다.

여기에서 오류의 스택 추적을 볼 수 있습니다.

위의 오류 세부 정보를 보면 이제 서비스에 영향을 미치는 특정 오류를 알 수 있습니다. 그러나 여기에 표시된 스택 추적은 축소되었으며 이 오류의 원인을 이해하기 어렵습니다. 이를 이해하려면 소스 맵을 업로드하여 오류 축소를 해제해야 합니다.

JS 오류를 축소 해제하기 위해 소스 맵 업로드

축소된 JavaScript는 대부분 브라우저의 오류 페이지에서 이해하기 어렵고 쓸모 없는 스택 추적을 생성합니다. 소스 맵을 업로드하면 이러한 오류가 이해할 수 있는 스택 추적으로 변환됩니다. 또한 코드 라인에 대한 유용한 참조를 제공하고 디버깅을 더 쉽게 만듭니다. UI, API 또는 npm 모듈을 통해 소스 맵을 New Relic에 업로드할 수 있습니다.

여기서는 New Relic UI를 사용하여 소스 맵을 업로드하고 JS 오류를 축소 해제합니다.

JS 오류 페이지에서 오류의 스택 추적으로 이동하여 확장합니다.

여기에 소스 맵을 업로드하는 옵션이 표시됩니다.

find file[파일 찾기를]클릭합니다.

이렇게 하면 로컬 저장소에서 소스 맵을 업로드할 수 있는 파일 탐색기 창이 열립니다. 프로젝트의 build/static/js 디렉터리에서 소스 맵을 찾아 업로드합니다.

소스 맵 파일의 파일 확장자는 .js.map 입니다. Relicstaurants는 소스 맵을 생성하도록 설정되어 있으며 build/static/js 디렉토리에서 찾을 수 있습니다. 프로젝트의 소스 맵을 생성하는 데 문제가 있는 경우 설명서에 따라 생성 방법을 알아보세요.

소스 맵이 성공적으로 업로드되면 오류가 축소되지 않은 것을 볼 수 있습니다.

여기에서 이 오류를 생성하는 특정 파일과 코드 줄을 볼 수 있습니다. 119행에서 Cart cannot be empty![Cart는 비워둘 수 없습니다!] **components/layouts/app/app-container/header/app-container-header.js 파일의 onClick** 이벤트와 연결되어 있으며 사용자에 대한 경고도 트리거합니다. 이 파일을 자세히 살펴보겠습니다!

선택한 IDE에서 애플리케이션을 열고 src/components/layouts/app/app-container/header/app-container-header.js 파일로 이동합니다. 표시된 코드를 자세히 살펴보십시오.

import { Button, Drawer, Table } from 'antd';
import Text from 'antd/lib/typography/Text';
import { orderList } from 'atoms/order-list.atom';
import { useState } from 'react';
import { Link } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { Logo, StyledHeader } from './app-header-styled';
import Navi from './navi-items';
import { useNavigate } from 'react-router';
const Header = () => {
const [isSidebarVisible, setIsSidebarVisible] = useState(false);
const [orderListState, setOrderList] = useRecoilState(orderList);
const navigate = useNavigate();
const onClose = () => {
setIsSidebarVisible(false);
};
const handleSidebarOpen = () => {
setIsSidebarVisible(true);
};
const itemQuantity = (list) => {
let totalItemQuantity = 0;
list.forEach((item) => (totalItemQuantity += item.count));
return totalItemQuantity;
};
const handleDeleteItem = (clickedRow) => {
const reducedData = orderListState.filter((item) =>
item.name === clickedRow.name ? false : true
);
setOrderList(reducedData);
};
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Count',
dataIndex: 'count',
key: 'count',
},
{
title: 'Price',
dataIndex: 'price',
key: 'price',
},
{
title: 'Delete',
render: (clickedRow) => (
<Button onClick={() => handleDeleteItem(clickedRow)}>-</Button>
),
},
];
return (
<StyledHeader>
<Link to="/">
<Logo>
<div>Relicstaurants</div>
<p>by New Relic</p>
</Logo>
</Link>
<Navi
sidebarVisible={handleSidebarOpen}
orderListLength={itemQuantity(orderListState)}
/>
<Drawer
size="large"
title="Cart"
placement="right"
onClose={onClose}
visible={isSidebarVisible}
>
<Table
dataSource={orderListState}
columns={columns}
pagination={false}
summary={(pageData) => {
let totalPrice = 0;
pageData.forEach(
({ price, count }) => (totalPrice += price * count)
);
return (
<>
<Table.Summary.Row>
<Table.Summary.Cell colSpan={2}>Total</Table.Summary.Cell>
<Table.Summary.Cell>
<Text type="danger">{totalPrice.toFixed(2)}</Text>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell colSpan={3}>
<Button
disabled={totalPrice > 0 ? false : true}
primary
onClick={() => {
setOrderList([]);
setIsSidebarVisible(false);
}}
>
Clear Cart
</Button>
</Table.Summary.Cell>
<Table.Summary.Cell>
<Button
id="pay"
primary
onClick={() => {
if (!(totalPrice > 0)) {
var err = new Error('Cart cannot be empty!');
newrelic.noticeError(err);
alert(err)
navigate('/')
setIsSidebarVisible(false);
} else {
navigate(`/payment`, { state: totalPrice });
setIsSidebarVisible(false);
}
}}
>
PAY
</Button>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
);
}}
/>
</Drawer>
</StyledHeader>
);
};
export default Header;
src/components/layouts/app/app-container/header/app-container-header.js

여기에서 Cart cannot be empty![장바구니는 비워둘 수 없다는] 오류에 유의하십시오 사용자가 실수로 빈 장바구니로 결제를 시도할 때만 발생합니다. 이 기능은 최종 사용자에게 빈 장바구니로 결제를 진행할 수 없음을 알리도록 코딩되어 있습니다. 이제 이 오류가 서비스에 영향을 미치지 않는다는 것을 알고 있습니다. 그러나 이 엣지 케이스를 처리하고 오류를 방지하는 더 좋은 방법이 있습니다.

애플리케이션 제공을 중지하려면 애플리케이션을 실행 중인 터미널에서 Ctrl+C 누르세요. 다음과 같이 src/components/layouts/app/app-container/header/app-container-header.js를 업데이트합니다.

import { Button, Drawer, Table } from 'antd';
import Text from 'antd/lib/typography/Text';
import { orderList } from 'atoms/order-list.atom';
import { Message } from 'components/common';
import { useState } from 'react';
import { Link } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { Logo, StyledHeader } from './app-header-styled';
import Navi from './navi-items';
import { useNavigate } from 'react-router';
const Header = () => {
const [isSidebarVisible, setIsSidebarVisible] = useState(false);
const [orderListState, setOrderList] = useRecoilState(orderList);
const navigate = useNavigate();
const onClose = () => {
setIsSidebarVisible(false);
};
const handleSidebarOpen = () => {
setIsSidebarVisible(true);
};
const itemQuantity = (list) => {
let totalItemQuantity = 0;
list.forEach((item) => (totalItemQuantity += item.count));
return totalItemQuantity;
};
const handleDeleteItem = (clickedRow) => {
const reducedData = orderListState.filter((item) =>
item.name === clickedRow.name ? false : true
);
setOrderList(reducedData);
};
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Count',
dataIndex: 'count',
key: 'count',
},
{
title: 'Price',
dataIndex: 'price',
key: 'price',
},
{
title: 'Delete',
render: (clickedRow) => (
<Button onClick={() => handleDeleteItem(clickedRow)}>-</Button>
),
},
];
return (
<StyledHeader>
<Link to="/">
<Logo>
<div>Relicstaurants</div>
<p>by New Relic</p>
</Logo>
</Link>
<Navi
sidebarVisible={handleSidebarOpen}
orderListLength={itemQuantity(orderListState)}
/>
<Drawer
size="large"
title="Cart"
placement="right"
onClose={onClose}
visible={isSidebarVisible}
>
{orderListState.length > 0 ? (
<Table
dataSource={orderListState}
columns={columns}
pagination={false}
summary={(pageData) => {
let totalPrice = 0;
pageData.forEach(
({ price, count }) => (totalPrice += price * count)
);
return (
<>
<Table.Summary.Row>
<Table.Summary.Cell colSpan={2}>Total</Table.Summary.Cell>
<Table.Summary.Cell>
<Text type="danger">{totalPrice.toFixed(2)}</Text>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell colSpan={3}>
<Button
disabled={totalPrice > 0 ? false : true}
primary
onClick={() => {
setOrderList([]);
setIsSidebarVisible(false);
}}
>
Clear Cart
</Button>
</Table.Summary.Cell>
<Table.Summary.Cell>
<Button
id="pay"
disabled={totalPrice > 0 ? false : true}
primary
onClick={() => {
navigate(`/payment`, { state: totalPrice });
setIsSidebarVisible(false);
}}
>
PAY
</Button>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
);
}}
/>
) : (
<Message>Nothing in cart</Message>
)}
</Drawer>
</StyledHeader>
);
};
export default Header;
src/components/layouts/app/app-container/header/app-container-header.js

여기에서 카트가 비어 있을 때 오류 대신 Nothing in cart[카트에 아무것도 없음] 메시지를 표시하는 파일을 수정했습니다. PAY 버튼은 최종 사용자가 장바구니에 항목을 담을 때까지 비활성화된 상태로 유지됩니다.

애플리케이션 다시 시작

애플리케이션을 수정했으므로 이제 로컬 서버를 다시 시작할 차례입니다.

bash
$
npm run build
$
npm run newstart

부하 생성기도 다시 시작하십시오.

bash
$
python3 simulator.py

중요

올바른 터미널 창에서 이러한 명령을 실행하고 있는지 확인하십시오. 해당 창이 더 이상 없으면 설정 절차의 단계를 따르십시오.

부하 생성기가 New Relic으로 데이터를 전송하기 시작하면 애플리케이션에서 더 이상 JavaScript 오류를 보고하지 않는다는 점에 유의하십시오.

요약

요약하자면, 애플리케이션에서 오류를 발견하고 New Relic 브라우저를 사용하여 다음을 수행했습니다.

  1. 오류율 검토
  2. 애플리케이션의 JS 오류 분석
  3. 오류 인스턴스 이해
  4. 소스 맵을 업로드하여 JS 오류 디버그

이 절차는 New Relic 브라우저로 웹 앱의 문제를 해결하는 방법을 알려주는 랩의 일부입니다. 다음으로 애플리케이션에서 프런트엔드 속도 저하를 디버깅해보십시오.

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.