• Log inStart now

Debug errors in your application

15 min

lab

This procedure is part of a lab that teaches you how to troubleshoot your web app with New Relic browser.

Each procedure in the lab builds upon the last, so make sure you've completed the last procedure, Instrument your application with our browser agent, before starting this one.

Until now, your application has been working fine. Users were able to place their orders and were satisfied with your service. But now that you have some insights in your application, you notice that it's showing some JavaScript errors.

JavaScript errors in relicstaurants

In this procedure, you use New Relic browser to find out what's causing these errors and debug your application timely.

Important

In order to see your data in New Relic, you need to enable browser monitoring for this procedure.

If you haven't already, instrument your app with our browser agent.

Debug frontend errors

The bad news is that you've confirmed there are some errors in your application. The good news is that you recently instrumented your application with our browser agent! Go to New Relic and sign into your account, if you haven't already.

Step 1 of 7

From the New Relic homepage, navigate to Browser and choose your Relicstaurants application.

select Reliqstaurants app

Step 2 of 7

Here, you see all the data related to your browser application including Page views with JavaScript errors, Core web vitals, User time on the site, Initial page load and route changes, and others.

image showing Reliqstaurants summary

Tip

Not seeing your data? Make sure you enabled browser monitoring and your load generator is running.

Step 3 of 7

Notice Page views with javascript errors.

image showing page views with javascript errors

Here, you see spikes showing that your application has some Javascript errors.

Step 4 of 7

Click on Page views with javascript errors.

Arrow pointing to JS errors tab

This takes you to JS errors page where you see all the JS errors along with Total error instances.

image showing JS errors

Step 5 of 7

Click on the Cart cannot be empty error for details.

box enclosing the error message

Here, you see errorMessage, INSTANCES, INTERACTIONS AFFECTED and other details related to your error.

image showing error details

Step 6 of 7

Next, navigate to Error Instances tab.

image showing error instances

Here, you see more details related to your particular error including Event Log, Stack trace, and other.

Step 7 of 7

Scroll down on the Error Instances page to view the Stack trace.

image showing stack trace

Here, you see the stack trace of your error.

Looking at the error details above, you now know the particular error affecting your services. However, the stack trace shown here is minified and it's hard to understand what's causing this error. To understand that, we need to upload the source map to un-minify the error.

Upload source map to un-minify JS error

Minified JavaScript mostly results in hard-to-understand, useless stack traces on browser's errors page. Uploading source maps converts these errors to understandable stack traces. It also provides a useful reference to code lines and makes it easier to debug. You can upload your soucre map to New Relic via UI, API or npm module.

Here, we use New Relic UI to upload source map and un-minify the JS error.

Step 1 of 5

From JS errors page, navigate to Stack trace of the error and expand it.

image showing expanded stack trace

Here, you see an option to upload source map.

Step 2 of 5

Click on find file.

image showing find file option to upload source map

This opens a file explorer window for you to upload source map from your local storage. Find and upload your source map from build/static/js directory of your project.

Tip

Source map files have a file extension of .js.map. Relicstaurants is set to generate source maps and you find it under build/static/js directory. If you're having trouble generating source maps for your project, follow our documentation to learn how to generate one.

Step 3 of 5

Once your source map is uploaded successfully, you see your error un-minified.

image showing unminified stack trace

Here, you see the particular file and the line of code that's generating this error. Notice that at line 119, the Cart cannot be empty! is associated with onClick event in components/layouts/app/app-container/header/app-container-header.js file and is also triggering an alert for the user. Let's take a closer look at this file!

Step 4 of 5

Open the application in the IDE of your choice and navigate to src/components/layouts/app/app-container/header/app-container-header.js file. Take a closer look at the shown code.

1
import { Button, Drawer, Table } from 'antd';
2
import Text from 'antd/lib/typography/Text';
3
import { orderList } from 'atoms/order-list.atom';
4
import { useState } from 'react';
5
import { Link } from 'react-router-dom';
6
import { useRecoilState } from 'recoil';
7
import { Logo, StyledHeader } from './app-header-styled';
8
import Navi from './navi-items';
9
import { useNavigate } from 'react-router';
10
11
const Header = () => {
12
const [isSidebarVisible, setIsSidebarVisible] = useState(false);
13
const [orderListState, setOrderList] = useRecoilState(orderList);
14
const navigate = useNavigate();
15
16
const onClose = () => {
17
setIsSidebarVisible(false);
18
};
19
const handleSidebarOpen = () => {
20
setIsSidebarVisible(true);
21
};
22
23
const itemQuantity = (list) => {
24
let totalItemQuantity = 0;
25
list.forEach((item) => (totalItemQuantity += item.count));
26
27
return totalItemQuantity;
28
};
29
30
const handleDeleteItem = (clickedRow) => {
31
const reducedData = orderListState.filter((item) =>
32
item.name === clickedRow.name ? false : true
33
);
34
setOrderList(reducedData);
35
};
36
37
const columns = [
38
{
39
title: 'Name',
40
dataIndex: 'name',
41
key: 'name',
42
},
43
{
44
title: 'Count',
45
dataIndex: 'count',
46
key: 'count',
47
},
48
{
49
title: 'Price',
50
dataIndex: 'price',
51
key: 'price',
52
},
53
{
54
title: 'Delete',
55
render: (clickedRow) => (
56
<Button onClick={() => handleDeleteItem(clickedRow)}>-</Button>
57
),
58
},
59
];
60
61
return (
62
<StyledHeader>
63
<Link to="/">
64
<Logo>
65
<div>Relicstaurants</div>
66
<p>by New Relic</p>
67
</Logo>
68
</Link>
69
<Navi
70
sidebarVisible={handleSidebarOpen}
71
orderListLength={itemQuantity(orderListState)}
72
/>
73
<Drawer
74
size="large"
75
title="Cart"
76
placement="right"
77
onClose={onClose}
78
visible={isSidebarVisible}
79
>
80
<Table
81
dataSource={orderListState}
82
columns={columns}
83
pagination={false}
84
summary={(pageData) => {
85
let totalPrice = 0;
86
87
pageData.forEach(
88
({ price, count }) => (totalPrice += price * count)
89
);
90
91
return (
92
<>
93
<Table.Summary.Row>
94
<Table.Summary.Cell colSpan={2}>Total</Table.Summary.Cell>
95
<Table.Summary.Cell>
96
<Text type="danger">{totalPrice.toFixed(2)}</Text>
97
</Table.Summary.Cell>
98
</Table.Summary.Row>
99
<Table.Summary.Row>
100
<Table.Summary.Cell colSpan={3}>
101
<Button
102
disabled={totalPrice > 0 ? false : true}
103
primary
104
onClick={() => {
105
setOrderList([]);
106
setIsSidebarVisible(false);
107
}}
108
>
109
Clear Cart
110
</Button>
111
</Table.Summary.Cell>
112
<Table.Summary.Cell>
113
<Button
114
id="pay"
115
primary
116
onClick={() => {
117
if (!(totalPrice > 0)) {
118
var err = new Error('Cart cannot be empty!');
119
newrelic.noticeError(err);
120
alert(err)
121
navigate('/')
122
setIsSidebarVisible(false);
123
} else {
124
navigate(`/payment`, { state: totalPrice });
125
setIsSidebarVisible(false);
126
}
127
}}
128
>
129
PAY
130
</Button>
131
</Table.Summary.Cell>
132
</Table.Summary.Row>
133
</>
134
);
135
}}
136
/>
137
</Drawer>
138
</StyledHeader>
139
);
140
};
141
142
export default Header;
src/components/layouts/app/app-container/header/app-container-header.js

Here, notice that the error Cart cannot be empty! only occurs whenever the user accidently tries to checkout with an empty cart. The function is coded to alert the end user that they can't proceed to checkout with an empty cart. You now know that this error will not affect your services. However, there are better ways to handle this edge case and avoid the error.

Step 5 of 5

Press Ctrl+C in the terminal that's running your application to stop serving it. Update the src/components/layouts/app/app-container/header/app-container-header.js as follows.

1
import { Button, Drawer, Table } from 'antd';
2
import Text from 'antd/lib/typography/Text';
3
import { orderList } from 'atoms/order-list.atom';
4
import { Message } from 'components/common';
5
import { useState } from 'react';
6
import { Link } from 'react-router-dom';
7
import { useRecoilState } from 'recoil';
8
import { Logo, StyledHeader } from './app-header-styled';
9
import Navi from './navi-items';
10
import { useNavigate } from 'react-router';
11
12
const Header = () => {
13
const [isSidebarVisible, setIsSidebarVisible] = useState(false);
14
const [orderListState, setOrderList] = useRecoilState(orderList);
15
const navigate = useNavigate();
16
17
const onClose = () => {
18
setIsSidebarVisible(false);
19
};
20
const handleSidebarOpen = () => {
21
setIsSidebarVisible(true);
22
};
23
24
const itemQuantity = (list) => {
25
let totalItemQuantity = 0;
26
list.forEach((item) => (totalItemQuantity += item.count));
27
28
return totalItemQuantity;
29
};
30
31
const handleDeleteItem = (clickedRow) => {
32
const reducedData = orderListState.filter((item) =>
33
item.name === clickedRow.name ? false : true
34
);
35
setOrderList(reducedData);
36
};
37
38
const columns = [
39
{
40
title: 'Name',
41
dataIndex: 'name',
42
key: 'name',
43
},
44
{
45
title: 'Count',
46
dataIndex: 'count',
47
key: 'count',
48
},
49
{
50
title: 'Price',
51
dataIndex: 'price',
52
key: 'price',
53
},
54
{
55
title: 'Delete',
56
render: (clickedRow) => (
57
<Button onClick={() => handleDeleteItem(clickedRow)}>-</Button>
58
),
59
},
60
];
61
62
return (
63
<StyledHeader>
64
<Link to="/">
65
<Logo>
66
<div>Relicstaurants</div>
67
<p>by New Relic</p>
68
</Logo>
69
</Link>
70
<Navi
71
sidebarVisible={handleSidebarOpen}
72
orderListLength={itemQuantity(orderListState)}
73
/>
74
<Drawer
75
size="large"
76
title="Cart"
77
placement="right"
78
onClose={onClose}
79
visible={isSidebarVisible}
80
>
81
{orderListState.length > 0 ? (
82
<Table
83
dataSource={orderListState}
84
columns={columns}
85
pagination={false}
86
summary={(pageData) => {
87
let totalPrice = 0;
88
89
pageData.forEach(
90
({ price, count }) => (totalPrice += price * count)
91
);
92
93
return (
94
<>
95
<Table.Summary.Row>
96
<Table.Summary.Cell colSpan={2}>Total</Table.Summary.Cell>
97
<Table.Summary.Cell>
98
<Text type="danger">{totalPrice.toFixed(2)}</Text>
99
</Table.Summary.Cell>
100
</Table.Summary.Row>
101
<Table.Summary.Row>
102
<Table.Summary.Cell colSpan={3}>
103
<Button
104
disabled={totalPrice > 0 ? false : true}
105
primary
106
onClick={() => {
107
setOrderList([]);
108
setIsSidebarVisible(false);
109
}}
110
>
111
Clear Cart
112
</Button>
113
</Table.Summary.Cell>
114
<Table.Summary.Cell>
115
<Button
116
id="pay"
117
disabled={totalPrice > 0 ? false : true}
118
primary
119
onClick={() => {
120
navigate(`/payment`, { state: totalPrice });
121
setIsSidebarVisible(false);
122
}}
123
>
124
PAY
125
</Button>
126
</Table.Summary.Cell>
127
</Table.Summary.Row>
128
</>
129
);
130
}}
131
/>
132
) : (
133
<Message>Nothing in cart</Message>
134
)}
135
</Drawer>
136
</StyledHeader>
137
);
138
};
139
140
export default Header;
src/components/layouts/app/app-container/header/app-container-header.js

Here, you modified the file show a message Nothing in cart instead of an error when the cart is empty. The PAY button remains disabled until the end users has items in their cart.

Restart your application

Now that you've fixed your application, it's time to restart your local server.

bash
$
npm run build
$
npm run newstart

Restart your load generator, as well.

bash
$
python3 simulator.py

Important

Make sure you're running these commands in the correct terminal windows. If you no longer have those windows, follow the steps in the setup procedure.

Once the load generator starts sending data to New Relic, notice that the application is no longer reporting JavaScript errors.

arrow pointing to straight error line

Summary

To recap, you observed an error in your application and used New Relic browser to:

  1. Review the error percentage
  2. Analyze the JS errors in your application
  3. Understand the error instance
  4. Debug the JS error by uploading source map

lab

This procedure is part of a lab that teaches you how to troubleshoot your web app with New Relic browser. Next, try to debug frontend slowness in your application.

Copyright © 2023 New Relic Inc.

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