• EnglishEspañol日本語한국어Português
  • ログイン今すぐ開始

この機械翻訳は、参考として提供されています。

英語版と翻訳版に矛盾がある場合は、英語版が優先されます。詳細については、このページを参照してください。

問題を作成する

ラボ パート 3: アプリケーションのエラーをデバッグする

ラボ

この手順は、New Relic ブラウザーを使用して Web アプリをトラブルシューティングする方法を説明するラボの一部です。

ラボの各手順は前回の手順に基づいているため、この手順を開始する前に、最後の手順で あるブラウザ エージェントを使用してアプリケーションをインストルメント化するを完了していることを確認してください。

これまで、アプリケーションは正常に動作していました。ユーザーは注文を行うことができ、サービスに満足しました。しかし、アプリケーションでいくつかの洞察を得たので、いくつかの JavaScript エラーが表示されていることに気付きました。

この手順では、New Relic ブラウザーを使用してこれらのエラーの原因を突き止め、アプリケーションをタイムリーにデバッグします。

重要

New Relic でデータを表示するには、この手順でを有効にする必要があります。

まだ行っていない場合は、 ブラウザ エージェントを使用してアプリをインストルメント化します

フロントエンドエラーをデバッグする

悪いニュースは、アプリケーションにいくつかのエラーがあることを確認したことです。良いニュースは、最近、アプリケーションに当社のブラウザー エージェントを組み込んだことです。アカウントにまだサインインしていない場合は、New Relic に移動してサインインします。

New Relic ホームページからBrowserに移動し、 Relicstaurantsアプリケーションを選択します。

ここには、Page views with JavaScript errorsCore web vitalsUser time on the siteInitial page load and route changes などを含む、 browserアプリケーションに関連するすべてのデータが表示されます。

ヒント

データが表示されませんか?ブラウザーの監視が有効になっており、Load Generator が実行されていることを確認してください。

Page views with javascript errors通知します。

ここでは、アプリケーションに Javascript エラーがあることを示すスパイクが表示されます。

Page views with javascript errorsをクリックします。

これにより、 JS errorsページに移動し、すべての JS エラーと合計エラー インスタンスが表示されます。

詳細については、 Cart cannot be emptyエラーをクリックしてください。

ここでは、エラーに関連するerrorMessageINSTANCESINTERACTIONS AFFECTEDなどの詳細が表示されます。

次に、 Error Instancesタブに移動します。

ここでは、 Event LogStack trace 、その他を含む特定のエラーに関連する詳細が表示されます。

Stack traceを表示するには、 Error Instancesページを下にスクロールします。

ここに、エラーのスタック トレースが表示されます。

上記のエラーの詳細を見ると、サービスに影響を与える特定のエラーがわかります。ただし、ここに示すスタック トレースは縮小されているため、このエラーの原因を理解するのは困難です。これを理解するには、ソース マップをアップロードしてエラーの縮小を解除する必要があります。

ソース マップをアップロードして 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!components/layouts/app/app- コンテナ/header/app- コンテナ-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

Load Generator も再起動します。

bash
$
python3 simulator.py

重要

これらのコマンドを正しいターミナル ウィンドウで実行していることを確認してください。これらのウィンドウが表示されなくなった場合は、 セットアップ手順の手順に従ってください。

Load Generator が New Relic へのデータ送信を開始すると、アプリケーションが JavaScript エラーを報告しなくなったことに注意してください。

概要

要約すると、アプリケーションでエラーを確認し、New Relic ブラウザーを使用して次のことを行いました。

  1. エラー率を確認する
  2. アプリケーションの JS エラーを分析する
  3. エラーインスタンスを理解する
  4. ソース マップをアップロードして JS エラーをデバッグする

ラボ

この手順は、New Relic ブラウザーを使用して Web アプリのトラブルシューティングを行う方法を説明するラボの一部です。次に、 アプリケーションのフロントエンドの遅さをデバッグしてみてください。

Copyright © 2024 New Relic株式会社。

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