Basic Example
Create an instance of the logger:
import { logger, http } from '@elliemae/pui-diagnostics';
const appLogger = logger({
transport: http('https://int.api.ellielabs.com/diagnostics/v2/logging'),
index: 'myapp',
team: 'my team',
appName: 'Hello World App',
});
Log messages with different log levels:
appLogger.debug('Detailed debug info');
appLogger.info('My application log message');
appLogger.audit('User performed action');
appLogger.warn('Something unexpected');
appLogger.error('Something went wrong');
appLogger.fatal('Application crashed');
Logging Exceptions
try {
// ...
} catch (ex) {
appLogger.error({
code: 'puiweb002',
message: 'Unable to send message',
exception: ex as Error,
});
}
Changing Default Log Level
The default log level is INFO. Messages below this level (e.g. DEBUG) are not logged.
import { LogLevels } from '@elliemae/pui-diagnostics';
appLogger.setLogLevel(LogLevels.DEBUG);
Updating Logger Options at Runtime
appLogger.setOptions({
environment: 'prod',
instanceId: 'new-instance',
customerId: 'cust-456',
userId: 'user-789',
appVersion: '2.0.0',
loanId: 'loan-guid',
});
Logging Unhandled Errors
Automatically captures unhandled promise rejections and uncaught errors:
import { logUnhandledErrors } from '@elliemae/pui-diagnostics';
logUnhandledErrors(appLogger);
Logging Web Vitals
Logs Core Web Vitals (LCP, INP, CLS) metrics automatically:
import { webvitals } from '@elliemae/pui-diagnostics';
webvitals(appLogger);
Controlling Log Volume with HTTP Transport Options
The http transport accepts an optional second argument to control batching, rate limiting, and sampling. These options help reduce API load from high-volume applications.
const transport = http('https://api.ellielabs.com/diagnostics/v2/logging', {
flushInterval: 15000, // flush every 15 seconds (default: 10000)
maxBatchSize: 50, // flush early at 50 buffered logs (default: 50)
maxLogsPerInterval: 200, // drop non-critical logs beyond 200 per window (default: 0 = unlimited)
samplingRate: 0.5, // send ~50% of non-critical logs (default: 1 = all)
});
const appLogger = logger({
transport,
index: 'myapp',
team: 'my team',
appName: 'Hello World App',
});
Options Reference
| Option | Type | Default | Description |
|---|---|---|---|
flushInterval | number | 10000 | Milliseconds between batch flushes for non-critical logs |
maxBatchSize | number | 50 | Flush the batch early when it reaches this size |
maxLogsPerInterval | number | 0 | Max non-critical logs per interval window. 0 = unlimited |
samplingRate | number | 1 | Sampling rate for non-critical logs (0–1). 1 = send all, 0.1 = send ~10% |
Note: WARN, ERROR, and FATAL logs are always sent immediately and are never subject to batching, rate limiting, or sampling.
Batched HTTP delivery
Uses sendBeacon, then fetch (keepalive) on the same body if needed; oversized multi-row batches may be split and retried after failures. Missing or throwing sendBeacon falls back to fetch. Failures log with console.warn. Critical logs: sendBeacon, then fetch for one message. Prefer a moderate maxBatchSize and compact payloads.
Using the Console Transport
For development or debugging, use the console transport instead of HTTP:
import { logger, Console } from '@elliemae/pui-diagnostics';
const appLogger = logger({
transport: Console(),
index: 'myapp',
team: 'my team',
appName: 'Hello World App',
});
Mirroring All Logs to Console
Send logs to your transport and the browser console:
const appLogger = logger({
transport: http('https://api.ellielabs.com/diagnostics/v2/logging'),
index: 'myapp',
team: 'my team',
appName: 'Hello World App',
logEverythingToConsole: true,
});
By default, only ERROR and FATAL logs are mirrored to the console.
PII Redaction
Every log that is sent applies PII redaction to the caller payload (the string or object you pass to debug, info, error, and so on). Base logger fields (index, team, userId, browser context, and so on) are trusted and are not re-scanned.
Redaction is key-aware:
| Field type | Examples | Behavior |
|---|---|---|
| Sensitive keys | email, ssn, password, phoneNumber, token, creditCardNumber, … | Entire value replaced with [Redacted] |
| Free-text keys | message, stack, description | Inline PII patterns (email, phone, SSN, address, credit card, credentials) |
| Base schema keys | userId, correlationId, loanId, context, … | Pass through unchanged |
| All other keys | duration, event, detail, contact, … | Pass through unchanged |
Guidelines for application logs
- Put human-readable text (errors, descriptions) in
message. That is where inline PII is scrubbed. - Use sensitive key names when logging known PII fields (for example
{ email: user.email }), not custom names likeuserEmail. - Structured telemetry (
duration,event, timingdetailobjects) is intentionally not regex-scanned. Do not embed PII in those values. - String-only logs (
appLogger.info('something happened')) are treated as{ message: '...' }and follow the free-text rules.
Stack traces
stackandError.stackuse a lighter pattern set (email, phone, SSN, password, credentials — not street address or credit card).- Only the first 8 KB of a stack trace is scanned; the remainder is sent unchanged for debugging.
Direct use of redactPii
The library exports redactPii for redacting arbitrary objects outside the logger:
import { redactPii } from '@elliemae/pui-diagnostics';
const safe = redactPii({
message: 'contact user@example.com',
duration: '512.3456789', // structured field — not regex-scanned
});