Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"./lib/derecursify": "./src/lib/derecursify.js",
"./lib/metadata-delegate": "./src/lib/metadata-delegate.js",
"./lib/callback-runner": "./src/lib/callback-runner.js",
"./lib/node-fallback-stack": "./src/lib/node-fallback-stack.js",
"./lib/path-normalizer": "./src/lib/path-normalizer.js",
"./lib/validators/string-with-length": "./src/lib/validators/string-with-length.js",
"./lib/validators/list-of-functions": "./src/lib/validators/list-of-functions.js",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as cloneClient } from './lib/clone-client'
export { default as jsonPayload } from './lib/json-payload'
export { default as intRange } from './lib/validators/int-range'
export { default as isError } from './lib/iserror'
export { default as nodeFallbackStack } from './lib/node-fallback-stack'
export { default as runSyncCallbacks } from './lib/sync-callback-runner'

export * from './common'
28 changes: 0 additions & 28 deletions packages/core/src/lib/node-fallback-stack.js

This file was deleted.

37 changes: 37 additions & 0 deletions packages/core/src/lib/node-fallback-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// The utilities in this file are used to save the stackframes from a known execution context
// to use when a subsequent error has no stack frames. This happens with a lot of
// node's builtin async callbacks when they return from the native layer with no context
// for example:
//
// fs.readFile('does not exist', (err) => {
// /* node 8 */
// err.stack = "ENOENT: no such file or directory, open 'nope'"
// /* node 4,6 */
// err.stack = "Error: ENOENT: no such file or directory, open 'nope'\n at Error (native)"
// })

interface NodeFallbackStack {
getStack: () => string | undefined
maybeUseFallbackStack: (err: Error, fallbackStack: string) => Error
}

const nodeFallbackStack: NodeFallbackStack = {
// Gets the stack string for the current execution context
getStack: () => {
// slice(3) removes the first line + this function's frame + the caller's frame,
// so the stack begins with the caller of this function
return (new Error()).stack?.split('\n').slice(3).join('\n')
},

// Given an Error and a fallbackStack from getStack(), use the fallbackStack
// if error.stack has no genuine stackframes (according to the example above)
maybeUseFallbackStack: (err, fallbackStack) => {
const lines = err.stack?.split('\n')
if (lines?.length === 1 || (lines?.length === 2 && /at Error \(native\)/.test(lines[1]))) {
err.stack = `${lines[0]}\n${fallbackStack}`
}
return err
}
}

export default nodeFallbackStack
5 changes: 2 additions & 3 deletions packages/plugin-contextualize/contextualize.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const { getStack } = require('@bugsnag/core/lib/node-fallback-stack')
const { cloneClient } = require('@bugsnag/core')
const { cloneClient, nodeFallbackStack } = require('@bugsnag/core')

module.exports = {
name: 'contextualize',
load: client => {
const contextualize = (fn, onError) => {
// capture a stacktrace in case a resulting error has nothing
const fallbackStack = getStack()
const fallbackStack = nodeFallbackStack.getStack()

const clonedClient = cloneClient(client)

Expand Down
6 changes: 3 additions & 3 deletions packages/plugin-intercept/intercept.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { getStack, maybeUseFallbackStack } = require('@bugsnag/core/lib/node-fallback-stack')
const { nodeFallbackStack } = require('@bugsnag/core')

module.exports = {
name: 'intercept',
Expand All @@ -10,12 +10,12 @@ module.exports = {
}

// capture a stacktrace in case a resulting error has nothing
const fallbackStack = getStack()
const fallbackStack = nodeFallbackStack.getStack()

return (err, ...data) => {
if (err) {
// check if the stacktrace has no context, if so, if so append the frames we created earlier
if (err.stack) maybeUseFallbackStack(err, fallbackStack)
if (err.stack) nodeFallbackStack.maybeUseFallbackStack(err, fallbackStack)
const event = client.Event.create(err, true, {
severity: 'warning',
unhandled: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-node-uncaught-exception/uncaught-exception.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { maybeUseFallbackStack } = require('@bugsnag/core/lib/node-fallback-stack')
const { nodeFallbackStack } = require('@bugsnag/core')

let _handler
module.exports = {
Expand All @@ -12,7 +12,7 @@ module.exports = {

// check if the stacktrace has no context, if so append the frames we created earlier
// see plugin-contextualize for where this is created
if (err.stack && c.fallbackStack) maybeUseFallbackStack(err, c.fallbackStack)
if (err.stack && c.fallbackStack) nodeFallbackStack.maybeUseFallbackStack(err, c.fallbackStack)

const event = c.Event.create(err, false, {
severity: 'error',
Expand Down