-
Notifications
You must be signed in to change notification settings - Fork 449
Expand file tree
/
Copy pathreport-error.ts
More file actions
93 lines (83 loc) · 2.74 KB
/
report-error.ts
File metadata and controls
93 lines (83 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import os from 'os'
import { dirname, join } from 'path'
import process, { version as nodejsVersion } from 'process'
import { fileURLToPath } from 'url'
import { inspect } from 'util'
import { type Event } from '@bugsnag/js'
import { getGlobalConfigStore } from '@netlify/dev-utils'
import { isCI } from 'ci-info'
import execa from '../execa.js'
import { cliVersion } from './utils.js'
const dirPath = dirname(fileURLToPath(import.meta.url))
interface ReportErrorConfig {
severity?: Event['severity']
metadata?: Record<string, Record<string, unknown>>
}
/**
* Report an error to telemetry
*/
export const reportError = async function (error: unknown, config: ReportErrorConfig = {}): Promise<void> {
if (isCI) {
return
}
// convert a NotifiableError to an error class
let err: Error
if (error instanceof Error) {
err = error
} else if (typeof error === 'string') {
err = new Error(error)
} else if (typeof error === 'object' && error !== null && ('message' in error || 'name' in error)) {
const errorObject = error as Record<string, unknown>
const message = typeof errorObject.message === 'string' ? errorObject.message : 'Unknown error'
err = new Error(message)
if (typeof errorObject.name === 'string') {
err.name = errorObject.name
}
if (typeof errorObject.stack === 'string') {
err.stack = errorObject.stack
}
} else {
err = new Error(typeof error === 'object' && error !== null ? inspect(error) : String(error))
}
const globalConfig = await getGlobalConfigStore()
let options: string
try {
options = JSON.stringify({
type: 'error',
data: {
message: err.message,
name: err.name,
stack: err.stack,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cause: (err as any).cause ? inspect((err as any).cause) : undefined,
severity: config.severity,
user: {
id: globalConfig.get('userId'),
},
metadata: config.metadata ? inspect(config.metadata) : undefined,
osName: `${os.platform()}-${os.arch()}`,
cliVersion,
nodejsVersion,
},
})
} catch {
// If stringify fails, we at least try to report a simplified error
options = JSON.stringify({
type: 'error',
data: {
message: `Error reporting failed: ${err.message}`,
name: 'ErrorReportingError',
severity: config.severity,
osName: `${os.platform()}-${os.arch()}`,
cliVersion,
nodejsVersion,
},
})
}
// spawn detached child process to handle send and wait for the http request to finish
// otherwise it can get canceled
await execa(process.execPath, [join(dirPath, 'request.js'), options], {
detached: true,
stdio: 'ignore',
})
}