or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser.mdchild-loggers.mdindex.mdlogger-configuration.mdlogger-methods.mdserializers.mdstreams.mdtransports.md

serializers.mddocs/

0

# Serializers

1

2

Custom object serialization and sensitive data redaction for secure and structured log output. Serializers control how objects are converted to JSON, while redaction ensures sensitive data is protected in log files.

3

4

## Capabilities

5

6

### Serializer Configuration

7

8

Configure custom serializers to control how specific object types are logged.

9

10

```typescript { .api }

11

interface LoggerOptions {

12

/** Custom serializers for object properties */

13

serializers?: { [key: string]: SerializerFn };

14

}

15

16

/**

17

* Function that transforms an object before logging

18

* @param value - The object to serialize

19

* @returns Serialized object suitable for JSON logging

20

*/

21

type SerializerFn = (value: any) => any;

22

```

23

24

**Usage Examples:**

25

26

```javascript

27

const logger = pino({

28

serializers: {

29

user: (user) => {

30

return {

31

id: user.id,

32

name: user.name,

33

// Exclude sensitive fields like password, email

34

};

35

},

36

request: (req) => {

37

return {

38

method: req.method,

39

url: req.url,

40

userAgent: req.headers['user-agent'],

41

// Exclude headers with sensitive data

42

};

43

},

44

error: (err) => {

45

return {

46

name: err.name,

47

message: err.message,

48

stack: err.stack,

49

code: err.code

50

};

51

}

52

}

53

});

54

55

// Serializers are applied to matching property names

56

logger.info({ user: userObject }, 'User action');

57

logger.error({ request: reqObject, error: errorObject }, 'Request failed');

58

```

59

60

### Standard Serializers

61

62

Use built-in serializers for common object types.

63

64

```typescript { .api }

65

const stdSerializers: {

66

/** HTTP request serializer */

67

req: SerializerFn;

68

69

/** HTTP response serializer */

70

res: SerializerFn;

71

72

/** Error object serializer */

73

err: SerializerFn;

74

75

/** Error with cause chain serializer */

76

errWithCause: SerializerFn;

77

78

/** Request serializer wrapper */

79

wrapRequestSerializer: (serializer: SerializerFn) => SerializerFn;

80

81

/** Response serializer wrapper */

82

wrapResponseSerializer: (serializer: SerializerFn) => SerializerFn;

83

84

/** Error serializer wrapper */

85

wrapErrorSerializer: (serializer: SerializerFn) => SerializerFn;

86

87

/** HTTP request mapping function */

88

mapHttpRequest: SerializerFn;

89

90

/** HTTP response mapping function */

91

mapHttpResponse: SerializerFn;

92

};

93

```

94

95

**Usage Examples:**

96

97

```javascript

98

// Use standard serializers

99

const logger = pino({

100

serializers: {

101

req: pino.stdSerializers.req,

102

res: pino.stdSerializers.res,

103

err: pino.stdSerializers.err

104

}

105

});

106

107

// Or use them directly

108

const logger = pino({

109

serializers: pino.stdSerializers

110

});

111

112

// Express.js example

113

app.use((req, res, next) => {

114

req.log = logger.child({ req });

115

res.log = logger.child({ res });

116

next();

117

});

118

119

app.get('/users', (req, res) => {

120

req.log.info('Fetching users'); // Includes serialized request

121

res.log.info('Users returned'); // Includes serialized response

122

});

123

```

124

125

## Redaction

126

127

### Redaction Configuration

128

129

Remove or censor sensitive data from log output automatically.

130

131

```typescript { .api }

132

interface LoggerOptions {

133

/** Redaction configuration */

134

redact?: string[] | RedactOptions;

135

}

136

137

interface RedactOptions {

138

/** Array of paths to redact using dot notation */

139

paths: string[];

140

141

/** Value to replace redacted data with (default: '[Redacted]') */

142

censor?: string | ((value: any, path: string[]) => any);

143

144

/** Remove the property entirely instead of censoring (default: false) */

145

remove?: boolean;

146

}

147

```

148

149

**Usage Examples:**

150

151

```javascript

152

// Simple redaction with array of paths

153

const logger = pino({

154

redact: ['password', 'creditCard', 'ssn']

155

});

156

157

logger.info({

158

username: 'john',

159

password: 'secret123',

160

creditCard: '4111-1111-1111-1111'

161

});

162

// Output: { username: 'john', password: '[Redacted]', creditCard: '[Redacted]' }

163

164

// Advanced redaction with options

165

const logger = pino({

166

redact: {

167

paths: ['user.password', 'payment.*.number', 'headers.authorization'],

168

censor: '***HIDDEN***',

169

remove: false

170

}

171

});

172

173

// Custom censor function

174

const logger = pino({

175

redact: {

176

paths: ['user.email'],

177

censor: (value) => {

178

if (typeof value === 'string' && value.includes('@')) {

179

const [local, domain] = value.split('@');

180

return `${local[0]}***@${domain}`;

181

}

182

return '[Redacted]';

183

}

184

}

185

});

186

```

187

188

### Redaction Path Syntax

189

190

Specify complex paths using dot notation and wildcards.

191

192

**Path Examples:**

193

194

```javascript

195

const logger = pino({

196

redact: {

197

paths: [

198

'password', // Top-level property

199

'user.password', // Nested property

200

'users.*.password', // Array elements

201

'config.database.password', // Deep nesting

202

'headers["x-api-key"]', // Bracket notation

203

'data[*].sensitive', // Array with wildcard

204

'nested.*.deep.secret' // Multiple levels with wildcard

205

]

206

}

207

});

208

209

// Test data

210

logger.info({

211

password: 'secret',

212

user: { password: 'user-secret' },

213

users: [

214

{ password: 'user1-secret' },

215

{ password: 'user2-secret' }

216

],

217

config: {

218

database: { password: 'db-secret' }

219

},

220

headers: {

221

'x-api-key': 'api-key-123'

222

}

223

});

224

// All specified paths will be redacted

225

```

226

227

## Custom Serializer Patterns

228

229

### Object Type Serializers

230

231

Create serializers for specific object types or classes.

232

233

**Usage Examples:**

234

235

```javascript

236

class User {

237

constructor(id, name, email, password) {

238

this.id = id;

239

this.name = name;

240

this.email = email;

241

this.password = password;

242

}

243

}

244

245

const logger = pino({

246

serializers: {

247

user: (user) => {

248

if (user instanceof User) {

249

return {

250

id: user.id,

251

name: user.name,

252

email: user.email.replace(/(.{2}).*@/, '$1***@')

253

};

254

}

255

return user;

256

},

257

database: (db) => {

258

return {

259

host: db.host,

260

port: db.port,

261

database: db.database,

262

// Never log connection strings or credentials

263

connected: db.connected

264

};

265

}

266

}

267

});

268

```

269

270

### Contextual Serializers

271

272

Create serializers that behave differently based on context.

273

274

**Usage Examples:**

275

276

```javascript

277

const logger = pino({

278

serializers: {

279

response: (res) => {

280

const serialized = {

281

statusCode: res.statusCode,

282

statusMessage: res.statusMessage,

283

headers: res.headers

284

};

285

286

// Include response body only for errors

287

if (res.statusCode >= 400 && res.body) {

288

serialized.body = res.body;

289

}

290

291

// Redact sensitive headers

292

if (serialized.headers) {

293

const { authorization, cookie, ...safeHeaders } = serialized.headers;

294

serialized.headers = safeHeaders;

295

}

296

297

return serialized;

298

},

299

performance: (perf) => {

300

return {

301

duration: perf.duration,

302

memory: Math.round(perf.memory / 1024 / 1024), // MB

303

cpu: Math.round(perf.cpu * 100) / 100 // Percentage

304

};

305

}

306

}

307

});

308

```

309

310

## Wrapper Serializers

311

312

### Extending Standard Serializers

313

314

Wrap standard serializers to add custom behavior while preserving base functionality.

315

316

**Usage Examples:**

317

318

```javascript

319

// Extend request serializer

320

const customReqSerializer = pino.stdSerializers.wrapRequestSerializer((req) => {

321

const serialized = pino.stdSerializers.req(req);

322

323

// Add custom fields

324

serialized.requestId = req.id;

325

serialized.userAgent = req.headers['user-agent'];

326

serialized.ip = req.ip || req.connection.remoteAddress;

327

328

// Remove sensitive headers

329

if (serialized.headers) {

330

delete serialized.headers.authorization;

331

delete serialized.headers.cookie;

332

}

333

334

return serialized;

335

});

336

337

// Extend error serializer

338

const customErrSerializer = pino.stdSerializers.wrapErrorSerializer((err) => {

339

const serialized = pino.stdSerializers.err(err);

340

341

// Add custom error properties

342

if (err.code) serialized.code = err.code;

343

if (err.statusCode) serialized.statusCode = err.statusCode;

344

if (err.context) serialized.context = err.context;

345

346

return serialized;

347

});

348

349

const logger = pino({

350

serializers: {

351

req: customReqSerializer,

352

err: customErrSerializer

353

}

354

});

355

```

356

357

## Advanced Redaction Patterns

358

359

### Dynamic Redaction

360

361

Configure redaction rules that change based on log level or context.

362

363

**Usage Examples:**

364

365

```javascript

366

function createLogger(logLevel) {

367

const redactPaths = ['password', 'token'];

368

369

// Add more redaction in production

370

if (process.env.NODE_ENV === 'production') {

371

redactPaths.push('user.email', 'user.phone', 'request.ip');

372

}

373

374

// Less redaction for debug level

375

if (logLevel === 'debug') {

376

return pino({

377

level: logLevel,

378

redact: {

379

paths: ['password'], // Only redact passwords for debugging

380

censor: '[DEBUG-REDACTED]'

381

}

382

});

383

}

384

385

return pino({

386

level: logLevel,

387

redact: {

388

paths: redactPaths,

389

remove: true // Remove entirely in production

390

}

391

});

392

}

393

```

394

395

### Conditional Redaction

396

397

Use censor functions to implement complex redaction logic.

398

399

**Usage Examples:**

400

401

```javascript

402

const logger = pino({

403

redact: {

404

paths: ['data.*'],

405

censor: (value, path) => {

406

// Different handling based on path

407

if (path.includes('email')) {

408

return value.replace(/(.{2}).*@(.*)/, '$1***@$2');

409

}

410

411

if (path.includes('phone')) {

412

return value.replace(/(\d{3})\d{3}(\d{4})/, '$1-***-$2');

413

}

414

415

if (path.includes('ssn')) {

416

return '***-**-' + value.slice(-4);

417

}

418

419

// Default redaction

420

return '[Redacted]';

421

}

422

}

423

});

424

425

logger.info({

426

data: {

427

email: 'user@example.com', // → us***@example.com

428

phone: '5551234567', // → 555-***-4567

429

ssn: '123456789' // → ***-**-6789

430

}

431

});

432

```

433

434

## Performance Considerations

435

436

### Serializer Performance

437

438

Optimize serializers for high-performance logging scenarios.

439

440

**Usage Examples:**

441

442

```javascript

443

// Efficient serializers avoid expensive operations

444

const logger = pino({

445

serializers: {

446

user: (user) => {

447

// Fast path for null/undefined

448

if (!user) return user;

449

450

// Object literal is faster than Object.assign

451

return {

452

id: user.id,

453

name: user.name

454

};

455

},

456

457

// Cache computed values when possible

458

request: (() => {

459

const headerCache = new WeakMap();

460

461

return (req) => {

462

if (!req) return req;

463

464

let headers = headerCache.get(req);

465

if (!headers) {

466

headers = {

467

'user-agent': req.headers['user-agent'],

468

'content-type': req.headers['content-type']

469

};

470

headerCache.set(req, headers);

471

}

472

473

return {

474

method: req.method,

475

url: req.url,

476

headers

477

};

478

};

479

})()

480

}

481

});

482

```

483

484

### Redaction Performance

485

486

Configure redaction for optimal performance with large objects.

487

488

**Usage Examples:**

489

490

```javascript

491

// Minimize redaction paths for better performance

492

const logger = pino({

493

redact: {

494

paths: [

495

'password', // Simple path

496

'user.password' // Avoid deep nesting when possible

497

],

498

censor: '[HIDDEN]', // String is faster than function

499

remove: false // Censoring is faster than removal

500

}

501

});

502

503

// For high-volume logging, consider pre-processing

504

function sanitizeForLogging(obj) {

505

const { password, secret, ...safe } = obj;

506

return safe;

507

}

508

509

logger.info(sanitizeForLogging(userData), 'User action');

510

```