Skip to content
Open
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
8 changes: 1 addition & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,7 @@ export const start = async <T extends SettingsDefinitionMap>(
if (err instanceof ExecutionError) {
throw err
}
censorLogs(() =>
logger.error({
name: err.name,
stack: err.stack,
message: err.message,
}),
)
censorLogs(() => logger.error(err))
})

if (
Expand Down
11 changes: 8 additions & 3 deletions src/util/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,21 @@ export const loggingContextMiddleware = (
// Obj is typed as "any" because it could be a variety of structures in the logger
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function censor(obj: any, censorList: CensorKeyValue[], throwOnError = false) {
// Name/message/stack are non-enumerable own properties on Error, so a plain
// JSON.stringify would silently drop them; pull them up before serializing.
const target =
obj instanceof Error ? { ...obj, name: obj.name, message: obj.message, stack: obj.stack } : obj

let stringified: string | undefined
try {
// JSON.stringify(obj) will fail if obj contains a circular reference or a bigint.
stringified = JSON.stringify(obj)
// JSON.stringify(target) will fail if target contains a circular reference or a bigint.
stringified = JSON.stringify(target)
} catch {
try {
// Retry with a bigint-safe replacer in case the failure was due to a bigint value.
// JSON.stringify with a replacer function is slower, so we only pay that cost when
// the fast path above actually fails, rather than on every call.
stringified = JSON.stringify(obj, (_key, value) => {
stringified = JSON.stringify(target, (_key, value) => {
return typeof value === 'bigint' ? value.toString() : value
})
} catch (e) {
Expand Down
16 changes: 16 additions & 0 deletions test/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,19 @@ test('properly handle nested bigint values', async (t) => {
const log = censor({ apiKey: 'mock-api-key', tx: { gasLimit: 21000n } }, CensorList.getAll())
t.deepEqual(log, { apiKey: '[API_KEY REDACTED]', tx: { gasLimit: '21000' } })
})

test('properly surfaces message/stack when given an Error', async (t) => {
const error = new Error('mock-api-key failure')
const log = censor(error, CensorList.getAll())
t.is(log.name, 'Error')
t.is(log.message, '[API_KEY REDACTED] failure')
t.truthy(log.stack)
})

test('properly surfaces custom enumerable properties alongside message/stack', async (t) => {
const error = Object.assign(new Error('boom'), { code: 'CALL_EXCEPTION' })
const log = censor(error, CensorList.getAll())
t.is(log.message, 'boom')
t.is(log.code, 'CALL_EXCEPTION')
t.truthy(log.stack)
})
Loading