fix(ui): sooth honeybader

Changes our error reporting strategy for Honeybadger from "report
everything logged by `console.error`" to "report everything caught by an
error boundary".

As before, Honeybadger still reports everything caught by
`window.onerror` as well.
pull/14584/head
Christopher Henn 2019-08-07 11:08:46 -07:00
parent 7d9ec64eec
commit 6d5ac71543
5 changed files with 64 additions and 35 deletions

View File

@ -1,31 +0,0 @@
import _ from 'lodash'
import HoneyBadger from 'honeybadger-js'
import {GIT_SHA} from 'src/shared/constants'
if (process.env.CLOUD === 'true') {
HoneyBadger.configure({
apiKey: process.env.HONEYBADGER_KEY,
revision: GIT_SHA,
environment: process.env.HONEYBADGER_ENV,
})
const override = () => {
if (!window || !window.console) {
return
}
const logError = console.error
console.error = function(...args) {
args.forEach(arg => {
if (_.isError(arg)) {
HoneyBadger.notify(arg)
}
})
logError.apply(console, args)
}
}
override()
}

View File

@ -1,5 +1,4 @@
import 'babel-polyfill'
import 'src/cloud/utils/overrides'
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
import React, {PureComponent} from 'react'

View File

@ -1,9 +1,12 @@
// Libraries
import React, {Component} from 'react'
import React, {Component, ErrorInfo} from 'react'
// Components
import DefaultErrorMessage from 'src/shared/components/DefaultErrorMessage'
// Utils
import {reportError, parseComponentName} from 'src/shared/utils/errors'
// Types
import {ErrorMessageComponent} from 'src/types'
@ -24,6 +27,10 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
return {error}
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
reportError(error, {component: parseComponentName(errorInfo)})
}
public render() {
const {error} = this.state

View File

@ -4,11 +4,14 @@ tslint:disable max-classes-per-file
*/
// Libraries
import React, {Component} from 'react'
import React, {Component, ErrorInfo} from 'react'
// Components
import DefaultErrorMessage from 'src/shared/components/DefaultErrorMessage'
// Utils
import {reportError, parseComponentName} from 'src/shared/utils/errors'
// Types
import {ErrorMessageComponent} from 'src/types'
@ -23,9 +26,11 @@ export function ErrorHandlingWith(Error: ErrorMessageComponent) {
private error: Error = null
public componentDidCatch(error) {
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.error = error
this.forceUpdate()
reportError(error, {component: parseComponentName(errorInfo)})
}
public render() {

View File

@ -0,0 +1,49 @@
import {ErrorInfo} from 'react'
import HoneyBadger from 'honeybadger-js'
import {CLOUD, GIT_SHA} from 'src/shared/constants'
if (CLOUD) {
HoneyBadger.configure({
apiKey: process.env.HONEYBADGER_KEY,
revision: GIT_SHA,
environment: process.env.HONEYBADGER_ENV,
})
}
interface AdditionalOptions {
component?: string
}
export const reportError = (
error: Error,
additionalOptions?: AdditionalOptions
): void => {
if (CLOUD) {
HoneyBadger.notify(error, additionalOptions)
}
}
/*
Parse React's error boundary info message to provide the name of the
component an error occured in.
For example, given the following info message:
The above error occurred in the <MePage> component:
in MePage (created by ErrorBoundary(MePage))
in ErrorBoundary (created by ErrorBoundary(MePage))
in ErrorBoundary(MePage) (created by Connect(ErrorBoundary(MePage)))
in Connect(ErrorBoundary(MePage)) (created by RouterContext)
in SpinnerContainer (created by SetOrg)
...
We will extract "MePage" as the component name.
*/
export const parseComponentName = (errorInfo: ErrorInfo): string => {
const componentName = errorInfo.componentStack
.trim()
.split('\n')
.map(s => s.split(' ')[1])[0]
return componentName
}