Skip to content

Commit

Permalink
Merge pull request #2245 from bugsnag/PLAT-12980-plugin-console-bread…
Browse files Browse the repository at this point in the history
…crumbs

Convert @bugsnag/plugin-console-breadcrumbs to TypeScript
  • Loading branch information
gingerbenw authored Oct 30, 2024
2 parents b2c7ccd + fbe3919 commit 3db887f
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 60 deletions.
2 changes: 1 addition & 1 deletion packages/core/lib/es-utils/reduce.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export default function reduce<T, U>(arr: T[], fn: (accum: any, item: T) => any, accum: any): any
export default function reduce<T, U>(arr: T[], fn: (accum: any, item: T, index: number, arr: T[]) => any, accum: any): any
47 changes: 0 additions & 47 deletions packages/plugin-console-breadcrumbs/console-breadcrumbs.js

This file was deleted.

17 changes: 15 additions & 2 deletions packages/plugin-console-breadcrumbs/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
{
"name": "@bugsnag/plugin-console-breadcrumbs",
"version": "8.1.1",
"main": "console-breadcrumbs.js",
"main": "dist/console-breadcrumbs.js",
"types": "dist/types/console-breadcrumbs.d.ts",
"exports": {
".": {
"types": "./dist/types/console-breadcrumbs.d.ts",
"default": "./dist/console-breadcrumbs.js",
"import": "./dist/console-breadcrumbs.mjs"
}
},
"description": "@bugsnag/js plugin to record console log method calls as breadcrumbs",
"homepage": "https://www.bugsnag.com/",
"repository": {
Expand All @@ -12,7 +20,7 @@
"access": "public"
},
"files": [
"*.js"
"dist"
],
"author": "Bugsnag",
"license": "MIT",
Expand All @@ -21,5 +29,10 @@
},
"peerDependencies": {
"@bugsnag/core": "^8.0.0"
},
"scripts": {
"build": "npm run build:npm",
"build:npm": "rollup --config rollup.config.npm.mjs",
"clean": "rm -rf dist/*"
}
}
6 changes: 6 additions & 0 deletions packages/plugin-console-breadcrumbs/rollup.config.npm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import createRollupConfig from "../../.rollup/index.mjs";

export default createRollupConfig({
input: "src/console-breadcrumbs.ts",
external: ["@bugsnag/core/lib/es-utils/filter", "@bugsnag/core/lib/es-utils/map", "@bugsnag/core/lib/es-utils/reduce"]
});
84 changes: 84 additions & 0 deletions packages/plugin-console-breadcrumbs/src/console-breadcrumbs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Client, Config, Plugin } from '@bugsnag/core'
import filter from '@bugsnag/core/lib/es-utils/filter'
import map from '@bugsnag/core/lib/es-utils/map'
import reduce from '@bugsnag/core/lib/es-utils/reduce'

type ConsoleMethod = 'log' | 'debug' | 'info' | 'warn' | 'error'

interface ClientWithInternals extends Client {
_config: Required<Config>
_isBreadcrumbTypeEnabled: (type: ConsoleMethod) => boolean
}

type ConsoleWithRestore = Console & {
[key in ConsoleMethod]: typeof console[ConsoleMethod] & { _restore: () => void }
}

/*
* Leaves breadcrumbs when console log methods are called
*/
const plugin: Plugin = {
load: (client) => {
const isDev = /^(local-)?dev(elopment)?$/.test((client as ClientWithInternals)._config.releaseStage)

if (isDev || !(client as ClientWithInternals)._isBreadcrumbTypeEnabled('log')) return

map(CONSOLE_LOG_METHODS, method => {
const original = console[method]
console[method] = (...args: any) => {
client.leaveBreadcrumb(
'Console output',
reduce(
args,
(accum, arg, i) => {
// do the best/simplest stringification of each argument
let stringified = '[Unknown value]'
// this may fail if the input is:
// - an object whose [[Prototype]] is null (no toString)
// - an object with a broken toString or @@toPrimitive implementation
try {
stringified = String(arg)
} catch (e) {}
// if it stringifies to [object Object] attempt to JSON stringify
if (stringified === '[object Object]') {
// catch stringify errors and fallback to [object Object]
try {
stringified = JSON.stringify(arg)
} catch (e) {}
}
accum[`[${i}]`] = stringified
return accum
},
{
severity: method.indexOf('group') === 0 ? 'log' : method
}
),
'log'
)
original.apply(console, args)
}
(console as ConsoleWithRestore)[method]._restore = () => {
console[method] = original
}
})
}
}

if (process.env.NODE_ENV !== 'production') {
plugin.destroy = () => {
const consoleWithRestore = console as ConsoleWithRestore
CONSOLE_LOG_METHODS.forEach(method => {
if (typeof consoleWithRestore[method]._restore === 'function') {
consoleWithRestore[method]._restore()
}
})
}
}

const CONSOLE_LOG_METHODS: ConsoleMethod[] = filter(
['log', 'debug', 'info', 'warn', 'error'],
method =>
typeof console !== 'undefined' && typeof console[method] === 'function'
)

export default plugin
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import plugin from '../'
import plugin from '../src/console-breadcrumbs'

import Client from '@bugsnag/core/client'

Expand Down Expand Up @@ -27,7 +27,7 @@ describe('plugin: console breadcrumbs', () => {
expect(c._breadcrumbs[2].metadata['[0]']).toBe('{"foo":[1,2,3,"four"]}')
expect(c._breadcrumbs[2].metadata['[1]']).toBe('{"pets":{"cat":"scratcher","dog":"pupper","rabbit":"sniffer"}}')
// undo the global side effects of wrapping console.* for the rest of the tests
plugin.destroy()
plugin.destroy?.()
})

it('should not throw when an object without toString is logged', () => {
Expand All @@ -36,48 +36,48 @@ describe('plugin: console breadcrumbs', () => {
expect(c._breadcrumbs.length).toBe(1)
expect(c._breadcrumbs[0].message).toBe('Console output')
expect(c._breadcrumbs[0].metadata['[0]']).toBe('[Unknown value]')
plugin.destroy()
plugin.destroy?.()
})

it('should not be enabled when enabledBreadcrumbTypes=[]', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: [], plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs.length).toBe(0)
plugin.destroy()
plugin.destroy?.()
})

it('should be enabled when enabledBreadcrumbTypes=null', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: null, plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs).toHaveLength(1)
plugin.destroy()
plugin.destroy?.()
})

it('should be enabled when enabledBreadcrumbTypes=["log"]', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', enabledBreadcrumbTypes: ['log'], plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs.length).toBe(1)
plugin.destroy()
plugin.destroy?.()
})

it('should be not enabled by default when releaseStage=development', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'development', plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs.length).toBe(0)
plugin.destroy()
plugin.destroy?.()
})

it('should be not enabled by default when releaseStage=dev', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'dev', plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs.length).toBe(0)
plugin.destroy()
plugin.destroy?.()
})

it('should be not enabled by default when releaseStage=local-dev', () => {
const c = new Client({ apiKey: 'aaaa-aaaa-aaaa-aaaa', releaseStage: 'local-dev', plugins: [plugin] })
console.log(123)
expect(c._breadcrumbs.length).toBe(0)
plugin.destroy()
plugin.destroy?.()
})
})
8 changes: 8 additions & 0 deletions packages/plugin-console-breadcrumbs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"target": "ES2020",
"types": ["node"]
}
}
1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
"packages/plugin-node-device",
"packages/plugin-node-surrounding-code",
"packages/plugin-node-uncaught-exception",
"packages/plugin-console-breadcrumbs",
"packages/plugin-browser-session",
"packages/browser"
],
Expand Down

0 comments on commit 3db887f

Please sign in to comment.