iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Logging (pino)

Structured logging is the difference between observable and opaque - and the diff in incident response time is measured in hours.

Node logging with pino

EXAMPLE
// npm install pino pino-http pino-pretty

// logger.js
import pino from 'pino';

const isDev = process.env.NODE_ENV !== 'production';

export const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  redact: {
    paths: ['req.headers.authorization', 'req.headers.cookie', '*.password', '*.token'],
    censor: '[REDACTED]',
  },
  transport: isDev
    ? { target: 'pino-pretty', options: { translateTime: 'HH:MM:ss', colorize: true } }
    : undefined,            // JSON to stdout in prod
});


// server.js
import express from 'express';
import pinoHttp from 'pino-http';
import { logger } from './logger.js';
import { randomUUID } from 'crypto';

const app = express();

app.use(pinoHttp({
  logger,
  genReqId: (req) => req.headers['x-request-id'] || randomUUID(),
  customLogLevel: (req, res, err) => {
    if (res.statusCode >= 500 || err) return 'error';
    if (res.statusCode >= 400) return 'warn';
    return 'info';
  },
  serializers: {
    req: (req) => ({ method: req.method, url: req.url, id: req.id }),
    res: (res) => ({ status: res.statusCode }),
  },
}));

app.get('/users/:id', async (req, res) => {
  req.log.info({ userId: req.params.id }, 'looking up user');
  const user = await db.users.findById(req.params.id);
  if (!user) {
    req.log.warn({ userId: req.params.id }, 'user not found');
    return res.status(404).send();
  }
  res.json(user);
});

// child loggers carry context
async function chargeOrder(order) {
  const log = logger.child({ orderId: order.id, customerId: order.customerId });
  log.info('charging');
  try {
    await stripe.charges.create({ amount: order.total });
    log.info({ amount: order.total }, 'charged');
  } catch (err) {
    log.error({ err }, 'charge failed');
    throw err;
  }
}

app.listen(3000, () => logger.info('listening on 3000'));

Why it matters

Log JSON to stdout. Let your platform (Datadog, Loki, CloudWatch) parse and index it. Always carry a request ID so you can trace a request across services. Always redact secrets, even in dev - habit makes leaks less likely.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import pino from 'pino';
const log = pino({ level: 'info' });
log.info({ user: 'ada' }, 'login');
Try it Yourself »

Discussion

Loading…