ืืืึทื ื ืืื ืืืขื ืืึธืื ืืืจ ืืืขืื ืคืึทืงืืืฉ-ืฆืืื ืืขืืช ืืจืึทืงืื ื ืืื ืึท ืจืขืึทืงื ืึทืคึผืืึทืงืืืฉืึทื. ื ืคืจืึธื ื-ืกืืฃ ืึทืคึผืืึทืงืืืฉืึทื ืืื ื ืืฉื ืืืคึผืืงืื ืืขื ืืฆื ืคึฟืึทืจ ืืขืืช ืืจืึทืงืื ื. ืขืืืขืืข ืงืึธืืคึผืึทื ืืขืก ืึธืคื ืฉืืขืื ืึทืืืขืง ืืฉืืง ืืจืึทืงืื ื, ืฆืืจืืงืงืืืขื ืฆื ืขืก ื ืึธื ืืึทืงืืืืขื ืืืืฉืึทื, ืืขืกืฅ, ืืื"ื ื. ืึธืืขืจ, ืืืื ืืืจ ืงืขื ืขื ืืืืฉื ืืืื ืคึผืจืึธืืืงื ืคึฟืึทืจ ืื ืืขืกืขืจ, ื ืึธืจ ืืึธื ืืึธืก!
1. ืคืืจืืืืก ืืึธื ืืืจ ืืึทืจืคึฟื ืกืขื ืืจื?
ืืื ืืืขืจื ืขืืขื ืืืจ ืืขื ื ืืื ืืขืจืขืกืืจื ืืื ืืจืึทืงืื ื ืืึทืื ืืขืฉืึทืก ืคึผืจืึธืืืงืฆืืข
ืฆื ืืืจ ืืจืึทืืื ืืึธืก ืืื ื ืืฉื ืืขื ืื?
ืึธืืงืื, ืืึธืืืจ ืงืืงื ืืื ืื ืคืจืืื.
ืื ืืืืคึผื ืกืืืืช ืคึฟืึทืจ ืืขืืืขืืึธืคึผืขืจืก ืฆื ื ืืฆื Sentry:
- ืึทืืึทืื ืืืจ ืฆื ืืืกืืืืื ืจืืกืงืก ืืืขื ืืืคึผืืืืื ื ืงืึธื ืืื ืขืจืจืึธืจืก
- ืืืืฃ QA ืืื ืงืึธื ืืขืกืืื ื
- ืืึทืงืืืขื ืฉื ืขื ื ืึธืืืึทืคืึทืงืืืฉืึทื ื ืืืขืื ืคึผืจืึธืืืขืืก
- ืคืืืืงืืื ืฆื ืืขืฉืืืื ื ืคืึทืจืจืืืื ืขืจืจืึธืจืก
- ืืึทืงืืืขื ืึท ืืึทืงืืืขื ืืืืึทื ืคืื ืขืจืจืึธืจืก ืืื ืื ืึทืืืื ืืึทืคืืืข
- ืกืึธืจื ืขืจืจืึธืจืก ืืืจื ืืึทื ืืฆืขืจ / ืืืขืืขืจืขืจ ืึธืคึผืฉื ืื
ืืืืคึผื ืกืืืืช ืคึฟืึทืจ ืกืขืึธ / ืคืืจื ืคึผืจืืืขืงื
- ืฉืคึผืึธืจื ืืขืื (ืกืขื ืืจื ืงืขื ืขื ืืืื ืืื ืกืืึทืืืจื ืืืืฃ ืืืื ืกืขืจืืืขืจืก)
- ืืึทืงืืืขื ืืึทื ืืฆืขืจ ืืึทืืขืจืงืื ืืขื
- ืคึฟืึทืจืฉืืืื ืืืึธืก ืืื ืคืึทืืฉ ืืื ืืืื ืคึผืจืืืขืงื ืืื ืคืึทืงืืืฉ ืฆืืื
- ืคืืจืฉืืื ื ืื ื ืืืขืจ ืคืื ืคึผืจืึธืืืขืืก ืืขื ืืฉื ืืึธืื ืืื ืืืื ืึทืคึผ
- ืืืืฃ ืืืจ ืืขืคึฟืื ืขื ืขืจืืขืจ ืืื ืืืื ืืขืืืขืืึธืคึผืขืจืก ืืขืืืื ืืืกืืืืงืก
ืืื ืืจืึทืืื ืื ืืขืืืขืืึธืคึผืขืจืก ืืืึธืื ืืืื ืืื ืืขืจืขืกืืจื ืืื ืืขื ืึทืจืืืงื ืขืจืฉืืขืจ. ืืืจ ืงืขื ื ืืืื ื ืืฆื ืื ืจืฉืืื ืคืื ืกืืืืช ืฆื ืืืืขืจืฆืืืื ืืืื ืืึธืกืกืขืก ืฆื ืืืกืฉืืืืขื ืกืขื ืืจื.
ืืืื ืึธืคึผืืขืืื ืืื ืื ืืขืฆืืข ื ืืืขืจ ืืืืฃ ืื ืืขืฉืขืคื ืจืฉืืื.
ืืขื ื ืืืจ ืฉืืื ืืื ืืขืจืขืกืืจื?
ืืืึธืก ืืื ืกืขื ืืจื?
Sentry ืืื ืึทื ืึธืคึฟื ืืงืืจ ืืฉืืง ืืจืึทืงืื ื ืึทืคึผืืึทืงืืืฉืึทื ืึทื ืืขืืคึผืก ืืขืืืขืืึธืคึผืขืจืก ืฆื ืฉืคึผืืจ ืืื ืคืึทืจืจืืืื ืงืจืึทืฉืื ืืื ืคืึทืงืืืฉ ืฆืืื. ืื ืืืืกื ื ืืฉื ืคืึทืจืืขืกื ืึทื ืื ืึทืคึผืืึทืงืืืฉืึทื ืึทืืึทืื ืืืจ ืฆื ืคืึทืจืืจืขืกืขืจื ืขืคืขืงืืืืืงืืึทื ืืื ืคึฟืึทืจืืขืกืขืจื ืืึทื ืืฆืขืจ ืืขืจืคืึทืจืื ื. ืกืขื ืืจื ืฉืืืฆื ืืืฉืึทืืืึทืกืงืจืืคึผื, ื ืึธืืข, ืคึผืืืืึธื, ืคืคึผ, ืจืืื, ื'ืืื ืืื ืื ืืขืจืข ืคึผืจืึธืืจืึทืืืื ื ืฉืคึผืจืึทืื.
2. ืืึธืืื ืืื ืฉืึทืคึฟื ืึท ืคึผืจืืืขืงื
- ืขืคึฟืขื ืขื ืืืื ืกืขื ืืจื ืืฉืืื. ืืืจ ืงืขื ืืึธืื ืฆื ืงืืึธืฅ ืืื. (ืืืืข ืืึธื ืึทื ืกืขื ืืจื ืงืขื ืขื ืืืื ืืื ืกืืึทืืืจื ืืืืฃ ืืืื ืกืขืจืืืขืจืก)
- ืืขืจ ืืืืึทืืขืจ ืฉืจืื ืืื ืฆื ืฉืึทืคึฟื ืึท ืคึผืจืืืขืงื
- ืืืืกืงืืืึทืื ืืืื ืฉืคึผืจืึทื ืคืื ืืขืจ ืจืฉืืื. (ืืืจ ืืืขืื ืืืืกืงืืืึทืื ืจืขืึทืงื. ืืจืืงื "ืฉืึทืคึฟื ืคึผืจืึธืืขืงื")
ืงืึทืกืืึทืืืื ืืืื ืึทืคึผืืึทืงืืืฉืึทื. ื ืืงืขืจืืืง ืืืึทืฉืคึผืื ืคืื ืืื ืฆื ืืืกืฉืืืืขื ืกืขื ืืจื ืืื ืึท ืงืึทื ืืืื ืขืจ ืงืขื ืขื ืืืื ืืขืืขื ืืื ืื:
import * as Sentry from '@sentry/browser';
// Sentry.init({
// dsn: "<https://[email protected]/1432138>"
// });
// should have been called before using it here
// ideally before even rendering your react app
class ExampleBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error, errorInfo) {
this.setState({ error });
Sentry.withScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
Sentry.captureException(error);
});
}
render() {
if (this.state.error) {
//render fallback UI
return (
<a onClick={() => Sentry.showReportDialog()}>Report feedback</a>
);
} else {
//when there's not an error, render children untouched
return this.props.children;
}
}
}
Sentry ืืื ืึท ื ืืฆืืง ืืืืืขืจื ืฆื ืืขืืคื ืืืจ ืืขืคึฟืื ืขื ืืืึธืก ืืืจ ืืึธื ืืึธื ืืืืึทืืขืจ. ืืืจ ืงืขื ืขื ื ืึธืืืืื ืื ืกืืขืคึผืก. ืืื ืืืืื ืฆื ืืืืึทืื ืืืจ ืืื ืฆื ืฉืึทืคึฟื ืืืื ืขืจืฉืืขืจ ืืขืืช ืืึทื ืืืขืจ. ืืจืืืก, ืืืจ ืืึธืื ืืืฉืืคื ืึท ืคึผืจืืืขืงื! ืืื ืก ืืึทื ืืืืฃ ืฆื ืื ืืืืึทืืขืจ ืฉืจืื
3. ืจืขืึทืืืจื ืืื ืกืขื ืืจื ืื ืืึทืืจืืืฉืึทื
ืืืจ ืืืื ืื ืกืืึทืืืจื ืื npm ืคึผืขืงื ืืื ืืืื ืคึผืจืืืขืงื.
npm i @sentry/browser
ืื ืืฉืึทืืืืข ืกืขื ืืจื ืืื ืืืื ืงืึทื ืืืื ืขืจ:
Sentry.init({
// dsn: #dsnUrl,
});
ืื DSN ืืื ืืืื ืืื ืคึผืจืึทืืืฉืขืงืก -> ืกืขืืืื ืืก -> ืงืืืขื ื ืงืื. ืืืจ ืงืขื ืขื ืืขืคึฟืื ืขื ืงืืืขื ื ืฉืืืกืืขื ืืื ืื ืืืื ืืึทืจ.
componentDidCatch(error, errorInfo) {
Sentry.withScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
Sentry.captureException(error);
});
}
4. ืืจืึทืงืื ื ืืขืจ ืขืจืฉืืขืจ ืืขืืช
ืคึฟืึทืจ ืืืึทืฉืคึผืื, ืืื ืืขืืืืื ื ืึท ืคึผืฉืื ืืืืืง ืึทืคึผืืึทืงืืืฉืึทื ืืื ืื Deezer API. ืืืจ ืงืขื ืขื ืืขื ืขืก
ืืืจ ืืึทืจืคึฟื ืฆื ืฉืึทืคึฟื ืึท ืงื ืขืคึผื ืืืึธืก ืจืืคื console.log ั ืืึทื ืืฆืขืจ.ืขืืึทืื. ื ืึธื ืืขื ืงืึทืืฃ ืืืจ ืืึธื ืืึทืงืืืขื ืึท ืืขืืช ืึธื ืืึธื: Uncaught TypeError (ืงืขื ืขื ื ืื ืืืืขื ืขื ืคืึทืจืืึธื ืคืื ืึทื ืืืคืืื ื email
) ืจืขืื ืฆื ืคืขืื ืืืง ืืึทื ืืฆืขืจ ืืืืคืขืฅ. ืืืจ ืงืขื ืขื ืืืื ื ืืฆื Javascript ืืืกื ืขื.
<button type="button" onClick={() => console.log(user.email)}>
Test Error button
</button>
ืืขืจ ืืื ืฆืขืจ ืงืึทื ืืืื ืขืจ ืงืืงื ืืื ืืึธืก:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Input, List, Skeleton, Avatar } from "antd";
import * as Sentry from "@sentry/browser";
import getList from "../store/actions/getList";
const Search = Input.Search;
const mapState = state => ({
list: state.root.list,
loading: state.root.loading
});
const mapDispatch = {
getList
};
class Container extends Component {
constructor(props) {
super(props);
Sentry.init({
dsn: "https://[email protected]/1417586",
});
}
componentDidCatch(error, errorInfo) {
Sentry.withScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
Sentry.captureException(error);
});
}
render() {
const { list, loading, getList } = this.props;
const user = undefined;
return (
<div className="App">
<button
type="button"
onClick={() => console.log(user.email)}
>
test error1
</button>
<div onClick={() => Sentry.showReportDialog()}>Report feedback1</div>
<h1>Music Finder</h1>
<br />
<Search onSearch={value => getList(value)} enterButton />
{loading && <Skeleton avatar title={false} loading={true} active />}
{!loading && (
<List
itemLayout="horizontal"
dataSource={list}
locale={{ emptyText: <div /> }}
renderItem={item => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={item.artist.picture} />}
title={item.title}
description={item.artist.name}
/>
</List.Item>
)}
/>
)}
</div>
);
}
}
export default connect(
mapState,
mapDispatch
)(Container);
ื ืึธื ืื ืืึทืืจืืืืื ื ืืขื ืงื ืขืคึผื, ืืืจ ืืึธื ืคึผืจืืืืจื ืขืก ืืื ืืขื ืืืขืืขืจืขืจ.
ืืืจ ืืึธืื ืืื ืืืขืจ ืขืจืฉืืขืจ ืืขืืช
ืืืื-ืื!
ืืืื ืืืจ ืืื ืืืืฃ ืื ืืขืืขืจ ืืขืืช, ืืืจ ืืืขื ืืขื ืึท ืึธื ืืืืื ืฉืคึผืืจ.
ืื ืึทืจืืืงืืขื ืงืืงื ืฉืืขืื. ืืึธื ืืืจ ืืึธืื ืืขืืขื ืืขืืช ืึทืจืืืงืืขื ืึธื ืคืืจืฉืืื ื ืืื ืื ืงืึธื ืืื. ืืืจื ืคืขืืืงืืึทื ืืืจ ืืขื ืขื ืืขืจืขืื ืืืขืื ืื ืืงืืจ ืืึทืคึผืข ืืื ReactJS ืืืืึทื ืืื ืืขื ืขื ื ืืฉื ืงืึทื ืคืืืืขืจื.
ืืื ืืืึธืื ืืืื ืืื ืฆื ืฆืืฉืืขืื ืื ืกืืจืึทืงืฉืึทื ื ืคึฟืึทืจ ืืึทืฉืืขืืืงื ืื ืืงืืจ ืืึทืคึผืข, ืึธืืขืจ ืืึธืก ืืืึธืื ืืึทืื ืืขื ืึทืจืืืงื ืคืื ืืขืจ ืืื ืืื ืืืขื.
ืืืจ ืงืขื ืขื ืืขืจื ืขื ืืขื ืืขืืข
ืงืกื ืืืงืก. ืื ื ืืฆื ืคืื ืืืขืืืขืจ ืืื ืกืืฃ ืคืื ื ืึทืคึผื
ืืงืขื. ืืืจ ืืึธืื ืืืืขืงื ืื ืืืกื ืขื ืคืื ืืืฉืึทืืืึทืกืงืจืืคึผื ืืื ืื ืคืจืืขืจืืืงืข ืคึผืึทืจืึทืืจืึทืคืก. ืึธืืขืจ, ืืืึธืก ืืืขืื ืืืจ ืืึธื ืืืขืื XHR ืขืจืจืึธืจืก?
ืกืขื ืืจื ืืืื ืืื ืื ืื ืืขืืช ืืึทื ืืืื ื. ืืื ืืขืืืืื ื ืขืก ืฆื ืฉืคึผืืจ ืึทืคึผื ืขืจืจืึธืจืก.
Sentry.captureException(err)
ืืืจ ืงืขื ืขื ืงืึทืกืืึทืืืื ืื ืืขืืช ื ืึธืืขื, ืืืจืื, ืืืืื ืืึทืื, ืืื ืฆืืง ืืึทื ืืฆืขืจ ืืึทืื ื ืืฆื ืืืื ืึทืคึผืืึทืงืืืฉืึทื, E- ืืจืืื, ืขืืง.
superagent
.get(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${query}`)
.set("X-RapidAPI-Key", #id_key)
.end((err, response) => {
if (err) {
Sentry.configureScope(
scope => scope
.setUser({"email": "[email protected]"})
.setLevel("Error")
);
return Sentry.captureException(err);
}
if (response) {
return dispatch(setList(response.body.data));
}
});
ืืื ืืืึธืื ืืื ืฆื ื ืืฆื ืึท ืืืฉืึทื ืขืจืืง ืคึฟืื ืงืฆืืข ืคึฟืึทืจ ืื ืืึทืคึผื ืึทืคึผื.
import * as Sentry from "@sentry/browser";
export const apiCatch = (error, getState) => {
const store = getState();
const storeStringify = JSON.stringify(store);
const { root: { user: { email } } } = store;
Sentry.configureScope(
scope => scope
.setLevel("Error")
.setUser({ email })
.setExtra("store", storeStringify)
);
// Sentry.showReportDialog(); - If you want get users feedback on error
return Sentry.captureException(error);
};
ืึทืจืืึทื ืคืืจ ืืขื ืคึฟืื ืงืฆืืข ืืื ืืืื ืึทืคึผื ืจืืคื.
export default query => (dispatch, getState) => {
superagent
.get(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${query}`)
.set("X-RapidAPI-Key", #id_key)
.end((error, response) => {
if (error) {
return apiCatch(error, getState)
}
if (response) {
return dispatch(setList(response.body.data));
}
});
};
ืืื ืก ืงืึธื ืืจืึธืืืจื ืื ืืขืืืึธืืก:
- setLevel ืึทืืึทืื ืืืจ ืฆื ืึทืจืืึทื ืืืืื ืึท ืืืจืื ืืขืืช ืืื ืื ืืืขืืืขืจ ืืึทืฉืืึธืจื. ืขืก ืืื ืคึผืจืึธืคึผืขืจืืืขืก - 'ืคืึทืืึทื', 'ืืขืืช', 'ืืืืจืขื ืื ื', 'ืืึธื', 'ืืื ืคึฟืึธืจืืึทืฆืืข, 'ืืืืึทื', 'ืงืจืืืืฉ').
- setUser ืืขืืคึผืก ืฆื ืจืึทืืขืืืขื ืงืืื ืืึทื ืืฆืขืจ ืืึทืื (ืฉืืึทื, ืืืืฆืคึผืึธืกื ืึทืืจืขืก, ืฆืึธืืื ื ืคึผืืึทื, ืืื"ื ื).
- setExtra ืึทืืึทืื ืืืจ ืฆื ืกืคึผืขืฆืืคืืฆืืจื ืงืืื ืืึทืื ืืืจ ืืึทืจืคึฟื, ืืืฉื, ืงืจืึธื.
ืืืื ืืืจ ืืืืื ืฆื ืืึทืงืืืขื ืืึทื ืืฆืขืจ ืืึทืืขืจืงืื ืืขื ืืืขืื ืึท ืืฉืืง, ืืืจ ืืึธื ื ืืฆื ืื showReportDialog ืคืื ืงืฆืืข.
Sentry.showReportDialog();
ืืกืงื ื:
ืืืึทื ื ืืืจ ืืืกืงืจืืืื ืืืื ืืืขื ืฆื ืืืกืฉืืืืขื ืกืขื ืืจื ืืื ืึท ืจืขืึทืงื ืึทืคึผืืึทืงืืืฉืึทื.
โ ืืขืืขืืจืึทื ืฉืืืขืกื ืืืจื
ืืงืืจ: www.habr.com