ΠΠ½Π΅Ρ ΡΠ΅ Π²ΠΈ ΠΏΡΠ΅Π²Π΅Π΄Π° ΠΏΡΠ΅Π· ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ Π² ΡΠ΅Π°Π»Π½ΠΎ Π²ΡΠ΅ΠΌΠ΅ Π² ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ React. ΠΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ Π·Π° ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π½Π΅ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π·Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ. ΠΡΠΊΠΎΠΈ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ΡΠ΅ΡΡΠΎ ΠΎΡΡΠ°Π²ΡΡ Π½Π°ΡΡΡΠ°Π½Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ, Π²ΡΡΡΠ°ΠΉΠΊΠΈ ΡΠ΅ ΠΊΡΠΌ Π½Π΅Π³ΠΎ ΡΠ»Π΅Π΄ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ, ΡΠ΅ΡΡΠΎΠ²Π΅ ΠΈ Ρ.Π½. ΠΡΠΏΡΠ΅ΠΊΠΈ ΡΠΎΠ²Π°, Π°ΠΊΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠ΅ ΠΏΡΠΎΠ΄ΡΠΊΡΠ° ΡΠΈ ΠΊΡΠΌ ΠΏΠΎ-Π΄ΠΎΠ±ΡΠΎ, ΡΠΎΠ³Π°Π²Π° ΠΏΡΠΎΡΡΠΎ Π³ΠΎ Π½Π°ΠΏΡΠ°Π²Π΅ΡΠ΅!
1. ΠΠ°ΡΠΎ ΠΈΠΌΠ°ΡΠ΅ Π½ΡΠΆΠ΄Π° ΠΎΡ Sentry?
ΠΡΠ΅Π΄ΠΏΠΎΠ»Π°Π³Π°ΠΌ, ΡΠ΅ ΡΠ΅ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΠ²Π°ΡΠ΅ ΠΎΡ ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ ΠΏΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΡΡΠ²ΠΎ.
Π‘ΠΌΡΡΠ°ΡΠ΅ Π»ΠΈ, ΡΠ΅ ΡΠΎΠ²Π° Π½Π΅ Π΅ Π΄ΠΎΡΡΠ°ΡΡΡΠ½ΠΎ?
ΠΠΎΠ±ΡΠ΅, Π½Π΅ΠΊΠ° Π΄Π° ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΡΡΠΈΡΠ΅.
ΠΡΠ½ΠΎΠ²Π½ΠΈ ΠΏΡΠΈΡΠΈΠ½ΠΈ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ Sentry Π·Π° ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈ:
- ΠΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π²ΠΈ Π΄Π° ΡΠ΅ ΠΎΡΡΡΠ²Π΅ΡΠ΅ ΠΎΡ ΡΠΈΡΠΊΠΎΠ²Π΅ΡΠ΅ ΠΏΡΠΈ Π²Π½Π΅Π΄ΡΡΠ²Π°Π½Π΅ Π½Π° ΠΊΠΎΠ΄ Ρ Π³ΡΠ΅ΡΠΊΠΈ
- ΠΠΎΠΌΠΎΠ³Π½Π΅ΡΠ΅ Π½Π° QA ΠΏΡΠΈ ΡΠ΅ΡΡΠ²Π°Π½Π΅ Π½Π° ΠΊΠΎΠ΄
- ΠΠΎΠ»ΡΡΠ°Π²Π°ΠΉΡΠ΅ Π±ΡΡΠ·ΠΈ ΠΈΠ·Π²Π΅ΡΡΠΈΡ Π·Π° ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ
- ΠΡΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ Π·Π° Π±ΡΡΠ·ΠΎ ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ
- ΠΠΎΠ»ΡΡΠ°Π²Π°Π½Π΅ Π½Π° ΡΠ΄ΠΎΠ±Π½ΠΎ ΠΏΠΎΠΊΠ°Π·Π²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ Π² Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠ°ΡΠΈΠ²Π½ΠΈΡ ΠΏΠ°Π½Π΅Π»
- Π‘ΠΎΡΡΠΈΡΠ°ΠΉΡΠ΅ Π³ΡΠ΅ΡΠΊΠΈΡΠ΅ ΠΏΠΎ ΡΠ΅Π³ΠΌΠ΅Π½Ρ Π½Π° ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»/Π±ΡΠ°ΡΠ·ΡΡ
ΠΡΠ½ΠΎΠ²Π½ΠΈ ΠΏΡΠΈΡΠΈΠ½ΠΈ Π·Π° ΠΈΠ·ΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π΅Π½ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡ / Π²ΠΎΠ΄Π΅Ρ ΠΏΡΠΎΠ΅ΠΊΡ
- Π‘ΠΏΠ΅ΡΡΠ΅ΡΠ΅ ΠΏΠ°ΡΠΈ (Sentry ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ Π½Π° Π²Π°ΡΠΈΡΠ΅ ΡΡΡΠ²ΡΡΠΈ)
- ΠΠΎΠ»ΡΡΠ΅ΡΠ΅ ΠΎΠ±ΡΠ°ΡΠ½Π° Π²ΡΡΠ·ΠΊΠ° ΠΎΡ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΠΈΡΠ΅
- Π Π°Π·Π±ΠΈΡΠ°Π½Π΅ ΠΊΠ°ΠΊΠ²ΠΎ Π½Π΅ Π΅ Π½Π°ΡΠ΅Π΄ Ρ Π²Π°ΡΠΈΡ ΠΏΡΠΎΠ΅ΠΊΡ Π² ΡΠ΅Π°Π»Π½ΠΎ Π²ΡΠ΅ΠΌΠ΅
- Π Π°Π·Π±ΠΈΡΠ°Π½Π΅ Π½Π° Π±ΡΠΎΡ Π½Π° ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈΡΠ΅, ΠΊΠΎΠΈΡΠΎ Ρ ΠΎΡΠ°ΡΠ° ΠΈΠΌΠ°Ρ Ρ Π²Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
- ΠΠΎΠΌΠΎΡ ΠΏΡΠΈ Π½Π°ΠΌΠΈΡΠ°Π½Π΅ Π½Π° ΠΌΠ΅ΡΡΠ°, ΠΊΡΠ΄Π΅ΡΠΎ Π²Π°ΡΠΈΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈ ΡΠ° Π½Π°ΠΏΡΠ°Π²ΠΈΠ»ΠΈ Π³ΡΠ΅ΡΠΊΠ°
ΠΠΈΡΠ»Ρ, ΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈΡΠ΅ Π±ΠΈΡ Π° ΡΠ΅ Π·Π°ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΠ²Π°Π»ΠΈ ΠΎΡ ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ Π½Π° ΠΏΡΡΠ²ΠΎ ΠΌΡΡΡΠΎ. ΠΠΎΠΆΠ΅ΡΠ΅ ΡΡΡΠΎ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ ΡΠΎΠ·ΠΈ ΡΠΏΠΈΡΡΠΊ Ρ ΠΏΡΠΈΡΠΈΠ½ΠΈ, Π·Π° Π΄Π° ΡΠ±Π΅Π΄ΠΈΡΠ΅ ΡΠ΅ΡΠ° ΡΠΈ Π΄Π° ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠ° Sentry.
ΠΠ½ΠΈΠΌΠ°Π²Π°ΠΉΡΠ΅ Ρ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ Π΅Π»Π΅ΠΌΠ΅Π½Ρ ΠΎΡ Π±ΠΈΠ·Π½Π΅Ρ ΡΠΏΠΈΡΡΠΊΠ°.
ΠΠ½ΡΠ΅ΡΠ΅ΡΡΠ²Π°ΡΠ΅ Π»ΠΈ ΡΠ΅ Π²Π΅ΡΠ΅?
ΠΠ°ΠΊΠ²ΠΎ Π΅ Sentry?
Sentry Π΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ Ρ ΠΎΡΠ²ΠΎΡΠ΅Π½ ΠΊΠΎΠ΄, ΠΊΠΎΠ΅ΡΠΎ ΠΏΠΎΠΌΠ°Π³Π° Π½Π° ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈΡΠ΅ Π΄Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Ρ ΠΈ ΠΊΠΎΡΠΈΠ³ΠΈΡΠ°Ρ ΡΡΠΈΠ²ΠΎΠ²Π΅ Π² ΡΠ΅Π°Π»Π½ΠΎ Π²ΡΠ΅ΠΌΠ΅. ΠΠ΅ Π·Π°Π±ΡΠ°Π²ΡΠΉΡΠ΅, ΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ ΡΡΡΠΎ Π²ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° ΡΠ²Π΅Π»ΠΈΡΠΈΡΠ΅ Π΅ΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΡΡΡΠ° ΠΈ Π΄Π° ΠΏΠΎΠ΄ΠΎΠ±ΡΠΈΡΠ΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΠΊΠΎΡΠΎ ΠΈΠ·ΠΆΠΈΠ²ΡΠ²Π°Π½Π΅. Sentry ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ° JavaScript, Node, Python, PHP, Ruby, Java ΠΈ Π΄ΡΡΠ³ΠΈ Π΅Π·ΠΈΡΠΈ Π·Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ°Π½Π΅.
2. ΠΠ»Π΅Π·ΡΠ΅ ΠΈ ΡΡΠ·Π΄Π°ΠΉΡΠ΅ ΠΏΡΠΎΠ΅ΠΊΡ
- ΠΡΠ²ΠΎΡΠ΅ΡΠ΅ ΡΠ²ΠΎΡ Π°ΠΊΠ°ΡΠ½Ρ Π² Sentry. ΠΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π½Π°Π»ΠΎΠΆΠΈ Π΄Π° Π²Π»Π΅Π·Π΅ΡΠ΅. (ΠΠΎΠ»Ρ, ΠΈΠΌΠ°ΠΉΡΠ΅ ΠΏΡΠ΅Π΄Π²ΠΈΠ΄, ΡΠ΅ Sentry ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ Π½Π° Π²Π°ΡΠΈΡΠ΅ ΡΡΡΠ²ΡΡΠΈ)
- Π‘Π»Π΅Π΄Π²Π°ΡΠ°ΡΠ° ΡΡΡΠΏΠΊΠ° Π΅ Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ΡΠ΅ ΠΏΡΠΎΠ΅ΠΊΡ
- ΠΠ·Π±Π΅ΡΠ΅ΡΠ΅ Π²Π°ΡΠΈΡ Π΅Π·ΠΈΠΊ ΠΎΡ ΡΠΏΠΈΡΡΠΊΠ°. (Π©Π΅ ΠΈΠ·Π±Π΅ΡΠ΅ΠΌ React. ΠΠ»ΠΈΠΊΠ½Π΅ΡΠ΅ Π²ΡΡΡ Ρ βΠ‘ΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° ΠΏΡΠΎΠ΅ΠΊΡβ)
ΠΠ°ΡΡΡΠΎΠΉΡΠ΅ Π²Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡΠ΅ ΠΎΡΠ½ΠΎΠ²Π΅Π½ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΡΠΎΠ²Π° ΠΊΠ°ΠΊ Π΄Π° ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠ°ΡΠ΅ Sentry Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ ΠΏΠΎ-Π΄ΠΎΠ»Ρ:
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. ΠΠ½ΡΠ΅Π³ΡΠΈΡΠ°Π½Π΅ Π½Π° React ΠΈ Sentry
Π’ΡΡΠ±Π²Π° Π΄Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΡΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠ° npm Π²ΡΠ² Π²Π°ΡΠΈΡ ΠΏΡΠΎΠ΅ΠΊΡ.
npm i @sentry/browser
ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠ°ΠΉΡΠ΅ Sentry Π²ΡΠ² Π²Π°ΡΠΈΡ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ:
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. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π³ΠΎ Π²ΠΈΠ΄ΠΈΡΠ΅
Π’ΡΡΠ±Π²Π° Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ΠΌ Π±ΡΡΠΎΠ½, ΠΊΠΎΠΉΡΠΎ Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ²Π° ΠΊΠΎΠ½Π·ΠΎΠ»Π΅Π½ Π΄Π½Π΅Π²Π½ΠΈΠΊ Ρ user.email. Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° Π΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΡΡΡΠ±Π²Π° Π΄Π° ΠΏΠΎΠ»ΡΡΠΈΠΌ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ Π·Π° Π³ΡΠ΅ΡΠΊΠ°: Uncaught TypeError (Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΡΠΎΡΠ΅ΡΠ΅ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎΡΠΎ ΠΎΡ undefined 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, Π·Π°ΡΠΎΡΠΎ ΡΠ΅ Π½Π΅ ΡΠ° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠ°Π½ΠΈ.
ΠΠΈΡ ΠΈΡΠΊΠ°Π» ΡΡΡΠΎ Π΄Π° ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Ρ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈ Π·Π° Π½Π°ΡΡΡΠΎΠΉΠΊΠ° Π½Π° ΠΊΠ°ΡΡΠ°ΡΠ° Π½Π° ΠΈΠ·ΡΠΎΡΠ½ΠΈΠΊΠ°, Π½ΠΎ ΡΠΎΠ²Π° ΡΠ΅ Π½Π°ΠΏΡΠ°Π²ΠΈ ΡΠ°Π·ΠΈ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΡ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎ-Π΄ΡΠ»Π³Π°, ΠΎΡΠΊΠΎΠ»ΠΊΠΎΡΠΎ Π²ΡΠ·Π½Π°ΠΌΠ΅ΡΡΠ²Π°Ρ .
ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΈΠ·ΡΡΠ°Π²Π°ΡΠ΅ ΡΠ°Π·ΠΈ ΡΠ΅ΠΌΠ°
5. Π£ΠΏΠΎΡΡΠ΅Π±Π° ΠΠ°ΡΠ°ΡΠ» Ρ ΠΊΡΠ°ΠΉΠ½Π° ΡΠΎΡΠΊΠ° API
ΠΠΠΠ Π. Π Π°Π·Π³Π»Π΅Π΄Π°Ρ ΠΌΠ΅ ΠΈΠ·ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π½Π° javascript Π² ΠΏΡΠ΅Π΄ΠΈΡΠ½ΠΈΡΠ΅ ΠΏΠ°ΡΠ°Π³ΡΠ°ΡΠΈ. ΠΠΎ ΠΊΠ°ΠΊΠ²ΠΎ ΠΏΡΠ°Π²ΠΈΠΌ Ρ XHR Π³ΡΠ΅ΡΠΊΠΈ?
Sentry ΡΡΡΠΎ ΠΈΠΌΠ° ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΎ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ Π³ΠΎ Π·Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ Π² API.
Sentry.captureException(err)
ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°ΡΠ΅ ΠΈΠΌΠ΅ΡΠΎ Π½Π° Π³ΡΠ΅ΡΠΊΠ°ΡΠ°, Π½ΠΈΠ²ΠΎΡΠΎ, Π΄Π° Π΄ΠΎΠ±Π°Π²ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ, ΡΠ½ΠΈΠΊΠ°Π»Π½ΠΈ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΠΊΠΈ Π΄Π°Π½Π½ΠΈ ΡΡΠ΅Π· Π²Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΈΠΌΠ΅ΠΉΠ» ΠΈ Ρ.Π½.
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));
}
});
ΠΠΈΡ ΠΈΡΠΊΠ°Π» Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ ΠΎΠ±ΡΠ° ΡΡΠ½ΠΊΡΠΈΡ Π·Π° catch API.
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);
};
ΠΠΌΠΏΠΎΡΡΠΈΡΠ°ΠΉΡΠ΅ ΡΠ°Π·ΠΈ ΡΡΠ½ΠΊΡΠΈΡ Π² API ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅.
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 Π²ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° Π²ΠΌΡΠΊΠ½Π΅ΡΠ΅ Π³ΡΠ΅ΡΠΊΠ° Π² Π½ΠΈΠ²ΠΎΡΠΎ Π² ΡΠ°Π±Π»ΠΎΡΠΎ Π·Π° ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΡΠ°ΡΠΎΠ²ΠΈΡ. Π’ΠΎΠΉ ΠΈΠΌΠ° ΡΠ²ΠΎΠΉΡΡΠ²Π° - "fatal", "error", "warning", "log", "info, "debug", "critical").
- setUser ΠΏΠΎΠΌΠ°Π³Π° Π·Π° Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ Π½Π° Π²ΡΡΠΊΠ°ΠΊΠ²ΠΈ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΠΊΠΈ Π΄Π°Π½Π½ΠΈ (ID, ΠΈΠΌΠ΅ΠΉΠ» Π°Π΄ΡΠ΅Ρ, ΠΏΠ»Π°Π½ Π·Π° ΠΏΠ»Π°ΡΠ°Π½Π΅ ΠΈ Ρ.Π½.).
- setExtra Π²ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° Π·Π°Π΄Π°Π΄Π΅ΡΠ΅ Π²ΡΡΠΊΠ°ΠΊΠ²ΠΈ Π΄Π°Π½Π½ΠΈ, ΠΎΡ ΠΊΠΎΠΈΡΠΎ ΡΠ΅ Π½ΡΠΆΠ΄Π°Π΅ΡΠ΅, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ ΠΌΠ°Π³Π°Π·ΠΈΠ½.
ΠΠΊΠΎ ΠΈΡΠΊΠ°ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΠΊΠ° ΠΎΠ±ΡΠ°ΡΠ½Π° Π²ΡΡΠ·ΠΊΠ° Π·Π° Π³ΡΠ΅ΡΠΊΠ°, ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ ΡΡΠ½ΠΊΡΠΈΡΡΠ° showReportDialog.
Sentry.showReportDialog();
ΠΠ°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅:
ΠΠ½Π΅Ρ ΠΎΠΏΠΈΡΠ°Ρ ΠΌΠ΅ Π΅Π΄ΠΈΠ½ ΠΎΡ Π½Π°ΡΠΈΠ½ΠΈΡΠ΅ Π·Π° ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠ°Π½Π΅ Π½Π° Sentry Π² ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° React.
β Telegram ΡΠ°Ρ ΠΎΡ
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: www.habr.com