Documentation Index Fetch the complete documentation index at: https://sedataai.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
A data processor is a pure function (data) => data that runs on every
attribute object the package emits. They’re the right place to redact, hash,
allow-list, or enrich attributes site-wide.
Signature
type DataProcessor = ( data : Record < string , any >) => Record < string , any >
You configure them on TelemetryConfig.dataProcessors:
const config : TelemetryConfig = {
// ...
dataProcessors: [
addEnv ,
redactPII ,
hashUserId ,
],
}
Processors run in order . Each receives the output of the previous one.
What gets processed
Every call to:
startActiveSpan(name, attributes, fn)
getHistogram(...)(value, attributes)
getIncrementCounter(...)(value, attributes)
…runs its attributes through every processor before recording. The session
id (mcp.session.id) is merged in before processors run, so processors see
it and can override or remove it.
Common recipes
const addEnv = ( data : Record < string , any >) => ({
... data ,
'deployment.env' : process . env . DEPLOY_ENV ?? 'dev' ,
'deployment.region' : process . env . AWS_REGION ?? 'local' ,
})
Redact specific keys
const SENSITIVE_KEYS = new Set ([ 'mcp.request.argument.api_key' , 'mcp.request.argument.password' ])
const redactKeys = ( data : Record < string , any >) => {
const out : Record < string , any > = {}
for ( const [ k , v ] of Object . entries ( data )) {
out [ k ] = SENSITIVE_KEYS . has ( k ) ? '[REDACTED]' : v
}
return out
}
Hash user identifiers
import { createHash } from 'node:crypto'
const hashUserIds = ( data : Record < string , any >) => {
const out = { ... data }
for ( const k of Object . keys ( out )) {
if ( k . endsWith ( 'user.id' ) && typeof out [ k ] === 'string' ) {
out [ k ] = createHash ( 'sha256' ). update ( out [ k ]). digest ( 'hex' ). slice ( 0 , 16 )
}
}
return out
}
Drop attributes by pattern
const dropDebug = ( data : Record < string , any >) => {
const out : Record < string , any > = {}
for ( const [ k , v ] of Object . entries ( data )) {
if ( ! k . startsWith ( 'debug.' )) out [ k ] = v
}
return out
}
Calling processors directly
You can run the configured chain manually for one-off uses:
const cleaned = telemetry . processTelemetryAttributes ({
'user.email' : 'jane@acme.com' ,
})
// → { 'mcp.session.id': '...', 'user.email': '[REDACTED:email]' }
This is useful when you’re building your own log lines and want them to share
the same redaction logic as your spans.
Order matters
A common bug: redact-then-add ordering. If you add deployment env after you
redact, the env keys are not redacted (which is usually fine but worth being
deliberate about).
dataProcessors : [
redactPII , // 1. scrub anything sensitive that came from user input
addEnv , // 2. add deployment metadata
enrichTrace , // 3. enrich with computed signals
]
Processors run on the hot path of every span and metric record. Keep them:
Pure — no I/O, no awaits.
Fast — use precompiled regexes, avoid full string clones when nothing
needs replacing.
Allocation-light — return the same object when nothing changed.
const redactIfNeeded = ( data : Record < string , any >) => {
let cloned : Record < string , any > | null = null
for ( const k of Object . keys ( data )) {
const v = data [ k ]
if ( typeof v === 'string' && PII_RE . test ( v )) {
cloned ??= { ... data }
cloned [ k ] = v . replace ( PII_RE , '[REDACTED]' )
}
}
return cloned ?? data // unchanged → return same reference
}
Next
PII sanitization A more focused recipe for the common case.
Custom spans & metrics Where processors fit in your custom code.