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

browser.mddocs/

0

# Browser Support

1

2

Browser-compatible logging with console output and transmit functionality for client-side applications. Pino provides a browser-specific build that maintains API compatibility while adapting to browser constraints.

3

4

## Capabilities

5

6

### Browser Logger

7

8

Use Pino in browser environments with console output and optional remote logging.

9

10

```typescript { .api }

11

/**

12

* Create a browser-compatible logger instance

13

* @param options - Browser-specific logger options

14

* @returns Logger instance optimized for browser use

15

*/

16

function pino(options?: BrowserLoggerOptions): Logger;

17

18

interface BrowserLoggerOptions extends LoggerOptions {

19

/** Browser-specific configuration */

20

browser?: BrowserOptions;

21

}

22

```

23

24

**Usage Examples:**

25

26

```javascript

27

// Basic browser logger

28

const logger = pino();

29

logger.info('Hello from browser'); // Outputs to console

30

31

// Browser logger with custom options

32

const logger = pino({

33

name: 'my-web-app',

34

level: 'debug',

35

browser: {

36

asObject: true,

37

transmit: {

38

level: 'error',

39

send: (level, logEvent) => {

40

// Send errors to monitoring service

41

fetch('/api/logs', {

42

method: 'POST',

43

body: JSON.stringify(logEvent)

44

});

45

}

46

}

47

}

48

});

49

```

50

51

### Browser Options

52

53

Configure browser-specific behavior and output formatting.

54

55

```typescript { .api }

56

interface BrowserOptions {

57

/** Create log objects instead of calling console methods directly */

58

asObject?: boolean;

59

60

/** Keep message formatting for deferred console rendering */

61

asObjectBindingsOnly?: boolean;

62

63

/** Custom write functions for different log levels */

64

write?: WriteFn | { [level: string]: WriteFn };

65

66

/** Enable serializers in browser (disabled by default) */

67

serialize?: boolean | string[];

68

69

/** Disable browser logging entirely */

70

disabled?: boolean;

71

72

/** Browser-specific formatters */

73

formatters?: {

74

level?: (label: string, number: number) => object;

75

log?: (object: Record<string, unknown>) => Record<string, unknown>;

76

};

77

78

/** Remote log transmission configuration */

79

transmit?: {

80

level?: string;

81

send: (level: string, logEvent: LogEvent) => void;

82

};

83

}

84

85

type WriteFn = (obj: object) => void;

86

```

87

88

## Console Output Modes

89

90

### Object Mode

91

92

Output structured log objects instead of formatted strings.

93

94

```typescript { .api }

95

interface BrowserOptions {

96

/** Create pino-like log objects instead of console calls */

97

asObject?: boolean;

98

}

99

```

100

101

**Usage Examples:**

102

103

```javascript

104

// Default console output

105

const logger = pino();

106

logger.info('Hello world'); // → console.info('Hello world')

107

108

// Object mode

109

const logger = pino({

110

browser: {

111

asObject: true

112

}

113

});

114

logger.info('Hello world');

115

// → console.info({msg: 'Hello world', level: 30, time: 1531171074631})

116

117

// With additional data

118

logger.info({ userId: 123 }, 'User action');

119

// → console.info({msg: 'User action', level: 30, time: 1531171074631, userId: 123})

120

```

121

122

### Deferred Formatting Mode

123

124

Preserve message formatting for better browser devtools rendering.

125

126

```typescript { .api }

127

interface BrowserOptions {

128

/** Keep messages unformatted for better browser devtools display */

129

asObjectBindingsOnly?: boolean;

130

}

131

```

132

133

**Usage Examples:**

134

135

```javascript

136

const logger = pino({

137

browser: {

138

asObjectBindingsOnly: true

139

}

140

});

141

142

logger.info('hello %s', 'world');

143

// → console.info({level: 30, time: 1531171074631}, 'hello %s', 'world')

144

// Browser devtools will format 'hello world' with proper styling

145

```

146

147

## Custom Write Functions

148

149

### Level-Specific Writers

150

151

Override default console methods with custom write functions.

152

153

```typescript { .api }

154

interface BrowserOptions {

155

/** Custom write functions */

156

write?: WriteFn | { [level: string]: WriteFn };

157

}

158

```

159

160

**Usage Examples:**

161

162

```javascript

163

// Single write function for all levels

164

const logger = pino({

165

browser: {

166

write: (obj) => {

167

// Custom logging implementation

168

const logEntry = {

169

timestamp: new Date().toISOString(),

170

level: obj.level,

171

message: obj.msg,

172

data: obj

173

};

174

175

// Send to custom logging service

176

window.customLogger.log(logEntry);

177

}

178

}

179

});

180

181

// Level-specific write functions

182

const logger = pino({

183

browser: {

184

write: {

185

info: (obj) => {

186

console.log('INFO:', obj);

187

},

188

error: (obj) => {

189

console.error('ERROR:', obj);

190

// Also send errors to error tracking

191

window.errorTracker.captureError(obj);

192

},

193

debug: (obj) => {

194

// Only log debug in development

195

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

196

console.debug('DEBUG:', obj);

197

}

198

}

199

}

200

}

201

});

202

```

203

204

## Serialization in Browser

205

206

### Serializer Control

207

208

Control which serializers are active in browser environments.

209

210

```typescript { .api }

211

interface BrowserOptions {

212

/** Enable serializers (disabled by default in browser) */

213

serialize?: boolean | string[];

214

}

215

```

216

217

**Usage Examples:**

218

219

```javascript

220

// Enable all serializers

221

const logger = pino({

222

serializers: {

223

error: (err) => ({

224

name: err.name,

225

message: err.message,

226

stack: err.stack

227

})

228

},

229

browser: {

230

serialize: true

231

}

232

});

233

234

// Enable specific serializers

235

const logger = pino({

236

serializers: {

237

req: reqSerializer,

238

res: resSerializer,

239

err: errSerializer

240

},

241

browser: {

242

serialize: ['err'] // Only error serializer active

243

}

244

});

245

246

// Explicitly disable standard error serializer

247

const logger = pino({

248

browser: {

249

serialize: ['!stdSerializers.err', 'custom']

250

}

251

});

252

```

253

254

## Remote Log Transmission

255

256

### Transmit Configuration

257

258

Send browser logs to remote endpoints for centralized logging.

259

260

```typescript { .api }

261

interface BrowserOptions {

262

/** Remote transmission configuration */

263

transmit?: {

264

level?: string;

265

send: (level: string, logEvent: LogEvent) => void;

266

};

267

}

268

269

interface LogEvent {

270

/** Timestamp when log method was called */

271

ts: number;

272

273

/** Array of arguments passed to log method */

274

messages: any[];

275

276

/** Child logger bindings hierarchy */

277

bindings: Bindings[];

278

279

/** Log level information */

280

level: {

281

label: string;

282

value: number;

283

};

284

}

285

```

286

287

**Usage Examples:**

288

289

```javascript

290

// Basic remote logging

291

const logger = pino({

292

browser: {

293

transmit: {

294

level: 'error',

295

send: (level, logEvent) => {

296

fetch('/api/logs', {

297

method: 'POST',

298

headers: { 'Content-Type': 'application/json' },

299

body: JSON.stringify({

300

level,

301

timestamp: logEvent.ts,

302

messages: logEvent.messages,

303

bindings: logEvent.bindings

304

})

305

}).catch(console.error);

306

}

307

}

308

}

309

});

310

311

// Advanced transmission with batching

312

const logger = pino({

313

browser: {

314

transmit: {

315

level: 'warn',

316

send: (() => {

317

const logBuffer = [];

318

let sendTimer;

319

320

return (level, logEvent) => {

321

logBuffer.push({ level, logEvent, timestamp: Date.now() });

322

323

// Batch send every 5 seconds or on critical errors

324

if (level === 'fatal' || level === 'error') {

325

sendLogs();

326

} else {

327

clearTimeout(sendTimer);

328

sendTimer = setTimeout(sendLogs, 5000);

329

}

330

};

331

332

function sendLogs() {

333

if (logBuffer.length === 0) return;

334

335

fetch('/api/logs/batch', {

336

method: 'POST',

337

headers: { 'Content-Type': 'application/json' },

338

body: JSON.stringify(logBuffer.splice(0))

339

}).catch(console.error);

340

}

341

})()

342

}

343

}

344

});

345

```

346

347

## Browser-Specific Patterns

348

349

### Error Tracking Integration

350

351

Integrate with browser error tracking services.

352

353

**Usage Examples:**

354

355

```javascript

356

// Sentry integration

357

const logger = pino({

358

browser: {

359

transmit: {

360

level: 'error',

361

send: (level, logEvent) => {

362

if (typeof Sentry !== 'undefined') {

363

Sentry.captureMessage(logEvent.messages[0], level);

364

365

// Add context from bindings

366

logEvent.bindings.forEach(binding => {

367

Sentry.setContext('logger', binding);

368

});

369

}

370

}

371

}

372

}

373

});

374

375

// Google Analytics event tracking

376

const logger = pino({

377

browser: {

378

transmit: {

379

level: 'info',

380

send: (level, logEvent) => {

381

if (typeof gtag !== 'undefined' && level === 'info') {

382

// Track important events

383

if (logEvent.messages[0].includes('user_action')) {

384

gtag('event', 'user_action', {

385

event_category: 'engagement',

386

event_label: logEvent.messages[0]

387

});

388

}

389

}

390

}

391

}

392

}

393

});

394

```

395

396

### Local Storage Logging

397

398

Store logs locally for offline scenarios.

399

400

**Usage Examples:**

401

402

```javascript

403

const logger = pino({

404

browser: {

405

write: {

406

error: (obj) => {

407

// Always show errors in console

408

console.error(obj);

409

410

// Store errors locally

411

try {

412

const errors = JSON.parse(localStorage.getItem('app_errors') || '[]');

413

errors.push({

414

...obj,

415

timestamp: Date.now(),

416

url: window.location.href,

417

userAgent: navigator.userAgent

418

});

419

420

// Keep only last 50 errors

421

if (errors.length > 50) {

422

errors.splice(0, errors.length - 50);

423

}

424

425

localStorage.setItem('app_errors', JSON.stringify(errors));

426

} catch (e) {

427

console.warn('Failed to store error in localStorage:', e);

428

}

429

}

430

}

431

}

432

});

433

434

// Function to retrieve stored errors

435

function getStoredErrors() {

436

try {

437

return JSON.parse(localStorage.getItem('app_errors') || '[]');

438

} catch (e) {

439

return [];

440

}

441

}

442

443

// Function to send stored errors when online

444

function syncStoredErrors() {

445

const errors = getStoredErrors();

446

if (errors.length > 0) {

447

fetch('/api/logs/sync', {

448

method: 'POST',

449

headers: { 'Content-Type': 'application/json' },

450

body: JSON.stringify(errors)

451

}).then(() => {

452

localStorage.removeItem('app_errors');

453

}).catch(console.error);

454

}

455

}

456

```

457

458

## Development vs Production

459

460

### Environment-Specific Configuration

461

462

Configure different behaviors for development and production builds.

463

464

**Usage Examples:**

465

466

```javascript

467

function createBrowserLogger() {

468

const isDevelopment = process.env.NODE_ENV === 'development';

469

470

return pino({

471

level: isDevelopment ? 'debug' : 'warn',

472

browser: {

473

asObject: isDevelopment, // Objects in dev, formatted in prod

474

disabled: false,

475

476

transmit: isDevelopment ? undefined : {

477

level: 'error',

478

send: (level, logEvent) => {

479

// Only transmit in production

480

fetch('/api/logs', {

481

method: 'POST',

482

body: JSON.stringify(logEvent)

483

});

484

}

485

},

486

487

write: isDevelopment ? undefined : {

488

// Custom production logging

489

error: (obj) => {

490

console.error(obj);

491

// Track errors in production

492

window.analytics?.track('error', obj);

493

}

494

}

495

}

496

});

497

}

498

499

const logger = createBrowserLogger();

500

```

501

502

### Browser Formatters

503

504

Custom formatting for log levels and objects in browser environments.

505

506

```typescript { .api }

507

interface BrowserOptions {

508

/** Browser-specific formatting functions */

509

formatters?: {

510

/** Changes the shape of the log level in browser output */

511

level?: (label: string, number: number) => object;

512

/** Changes the shape of the log object in browser output */

513

log?: (object: Record<string, unknown>) => Record<string, unknown>;

514

};

515

}

516

```

517

518

**Usage Examples:**

519

520

```javascript

521

// Custom level formatting

522

const logger = pino({

523

browser: {

524

formatters: {

525

level: (label, number) => {

526

return {

527

severity: label.toUpperCase(),

528

levelNum: number,

529

timestamp: Date.now()

530

};

531

},

532

log: (object) => {

533

// Add browser-specific context

534

return {

535

...object,

536

userAgent: navigator.userAgent,

537

url: window.location.href,

538

viewport: {

539

width: window.innerWidth,

540

height: window.innerHeight

541

}

542

};

543

}

544

}

545

}

546

});

547

548

logger.info({ action: 'page_load' }, 'Page loaded');

549

// Output includes custom formatting with browser context

550

```

551

552

### Bundle Size Optimization

553

554

Minimize browser bundle size when using Pino.

555

556

**Usage Examples:**

557

558

```javascript

559

// Import only what you need

560

import pino from 'pino/browser';

561

562

// Or use a custom build

563

const logger = pino({

564

browser: {

565

// Disable features not needed in browser

566

serialize: false,

567

disabled: process.env.NODE_ENV === 'test'

568

}

569

});

570

571

// Tree-shake unused features in webpack

572

module.exports = {

573

resolve: {

574

alias: {

575

'pino': 'pino/browser'

576

}

577

}

578

};

579

```