From 274ae35f774c6cb268f79f90d2e6b95c2be89f4c Mon Sep 17 00:00:00 2001 From: Memo Date: Thu, 23 Jul 2026 14:00:24 +0200 Subject: [PATCH] fix(next): thread redact through createInstrumentation().register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit register() re-initialised the global logger without threading options.redact and then locked it, clobbering the redact config createEvlog applied at import — silently disabling redaction for the documented Next.js instrumentation setup. Next-only: the handler path (#409) and both nitro plugins already thread it. Adds the redact option to InstrumentationOptions (matching the handler path's raw pass-through; the logger resolves it internally) and a regression test on the initLogger spy. --- .changeset/fix-next-instrumentation-redact.md | 5 +++++ packages/evlog/src/next/instrumentation-create.ts | 5 ++++- packages/evlog/test/next/instrumentation.test.ts | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-next-instrumentation-redact.md diff --git a/.changeset/fix-next-instrumentation-redact.md b/.changeset/fix-next-instrumentation-redact.md new file mode 100644 index 00000000..abe638e0 --- /dev/null +++ b/.changeset/fix-next-instrumentation-redact.md @@ -0,0 +1,5 @@ +--- +"evlog": patch +--- + +fix(next): thread `redact` through `createInstrumentation().register()` — it previously re-initialised the logger without redaction and locked it, silently disabling `redact` configured for the Next.js instrumentation path diff --git a/packages/evlog/src/next/instrumentation-create.ts b/packages/evlog/src/next/instrumentation-create.ts index cfed3c23..f6c3b98a 100644 --- a/packages/evlog/src/next/instrumentation-create.ts +++ b/packages/evlog/src/next/instrumentation-create.ts @@ -1,5 +1,5 @@ import { registerDiskPrettyErrorSnippetReader } from '../shared/register-disk-snippet' -import type { DrainContext, EnvironmentContext, LogLevel, Log, SamplingConfig } from '../types' +import type { DrainContext, EnvironmentContext, LogLevel, Log, RedactConfig, SamplingConfig } from '../types' import type { NextInstrumentationErrorContext, NextInstrumentationRequest, @@ -58,6 +58,8 @@ export interface InstrumentationOptions { stringify?: boolean /** Drain callback called with every emitted event. */ drain?: (ctx: DrainContext) => void | Promise + /** Auto-redaction configuration for PII protection. @default true in production */ + redact?: boolean | RedactConfig /** Capture stdout/stderr as structured log events (Node.js only). */ captureOutput?: boolean | CaptureOutputOptions } @@ -204,6 +206,7 @@ export function createInstrumentation(options: InstrumentationOptions = {}): Ins minLevel: options.minLevel, stringify: options.stringify, drain: options.drain, + redact: options.redact, }) lockLogger() if (process.env.NEXT_RUNTIME === 'nodejs') { diff --git a/packages/evlog/test/next/instrumentation.test.ts b/packages/evlog/test/next/instrumentation.test.ts index ec30cf9c..4f35c534 100644 --- a/packages/evlog/test/next/instrumentation.test.ts +++ b/packages/evlog/test/next/instrumentation.test.ts @@ -81,6 +81,7 @@ describe('createInstrumentation', () => { drain: drainMock, sampling: { rates: { info: 50 } }, stringify: false, + redact: { paths: ['error.message', 'error.cause'] }, }) await runRegister(register) @@ -93,6 +94,7 @@ describe('createInstrumentation', () => { expect(config.drain).toBe(drainMock) expect(config.sampling).toEqual({ rates: { info: 50 } }) expect(config.stringify).toBe(false) + expect(config.redact).toEqual({ paths: ['error.message', 'error.cause'] }) }) it('register() with captureOutput patches stdout and stderr', async () => {