Auto-Redaction
Wide events capture comprehensive context, which makes it easy to accidentally log sensitive data. Auto-redaction scrubs PII from events before console output and before any drain sees the data.
Redaction is enabled by default in production (NODE_ENV === 'production'). In development, it is off so you see full values for debugging. No configuration needed — just deploy.
Opting Out
If you need to disable redaction in production:
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
redact: false,
},
})
import { createEvlog } from 'evlog/next'
export const { withEvlog, useLogger } = createEvlog({
service: 'my-app',
redact: false,
})
import { initLogger } from 'evlog'
initLogger({
env: { service: 'my-app' },
redact: false,
})
You can also enable redaction explicitly in development with redact: true.
Smart Masking
Built-in patterns use partial masking instead of flat [REDACTED] — preserving enough context for debugging while protecting the actual data.
| Pattern | Example Input | Masked Output |
|---|---|---|
creditCard | 4111111111111111 | ****1111 |
email | alice@example.com | a***@***.com |
ipv4 | 192.168.1.100 | ***.***.***.100 |
phone | +33 6 12 34 56 78 | +33 ****5678 |
jwt | eyJhbGciOiJIUzI1NiIs... | eyJ***.*** |
bearer | Bearer sk_live_abc123... | Bearer *** |
iban | FR76 3000 6000 0112 ...189 | FR76****189 |
127.0.0.1 and 0.0.0.0 are excluded from IPv4 masking since they are not real client addresses.Configuration
Custom Paths
Add dot-notation paths to redact specific fields with [REDACTED], on top of the built-in patterns:
evlog: {
redact: {
paths: ['user.password', 'headers.authorization'],
}
}
Path-based redaction replaces the entire value with the replacement string (default [REDACTED]), regardless of content.
Selective Built-ins
Pick only the patterns you need:
evlog: {
redact: {
builtins: ['email', 'creditCard'],
}
}
Custom Patterns
Add your own regex patterns. These use the flat replacement string, not smart masking:
evlog: {
redact: {
patterns: [/SECRET_\w+/g, /sk_live_\w+/g],
replacement: '***',
}
}
Disable Built-ins
If you only want custom redaction:
evlog: {
redact: {
builtins: false,
paths: ['user.ssn'],
patterns: [/INTERNAL_\w+/g],
}
}
Configuration Reference
| Option | Type | Default | Description |
|---|---|---|---|
redact | boolean | RedactConfig | true in production | Enabled by default in production. false to disable. Object for fine-grained control |
paths | string[] | undefined | Dot-notation paths to redact entirely (e.g. user.password) |
patterns | RegExp[] | undefined | Custom regex patterns. Uses flat replacement string |
builtins | false | string[] | All enabled | false disables built-ins. Array selects specific ones |
replacement | string | '[REDACTED]' | Replacement string for paths and custom patterns. Built-in patterns use smart masking instead |
Available built-in names: creditCard, email, ipv4, phone, jwt, bearer, iban.
How It Works
Redaction runs inside the emit pipeline, after the wide event is fully built but before any output:
- Path redaction — targeted fields replaced with
[REDACTED] - Smart masking — built-in patterns scan all string values recursively with partial masking
- Pattern redaction — custom regex patterns scan all string values with flat replacement
- Console output — masked event printed to stdout
- Drain — masked event sent to external services
Production Example
Redaction is already on by default in production. Combine with sampling for a typical setup:
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
env: { service: 'my-app' },
},
$production: {
evlog: {
sampling: {
rates: { info: 10, debug: 0 },
keep: [{ status: 400 }, { duration: 1000 }],
},
},
},
})
import { createEvlog } from 'evlog/next'
export const { withEvlog, useLogger } = createEvlog({
service: 'my-app',
sampling: {
rates: { info: 10, debug: 0 },
keep: [{ status: 400 }, { duration: 1000 }],
},
})
import { initLogger } from 'evlog'
initLogger({
env: { service: 'my-app' },
sampling: {
rates: { info: 10, debug: 0 },
keep: [{ status: 400 }, { duration: 1000 }],
},
})
Before / After
Without redaction, sensitive data lands in your logs and drains:
{
"user": { "email": "alice@example.com", "ip": "192.168.1.42" },
"payment": { "card": "4111111111111111" },
"auth": "Bearer sk_live_abc123def456"
}
With redact: true:
{
"user": { "email": "a***@***.com", "ip": "***.***.***.42" },
"payment": { "card": "****1111" },
"auth": "Bearer ***"
}
Same debugging context, no PII in your Axiom/Datadog/Sentry.
Next Steps
- Best Practices - Security guidelines and production checklist
- Sampling - Control log volume in production
- Configuration - Full configuration reference