DEV Community

EME GUG
EME GUG

Posted on

Logging best practices: stop using console.log

Your production app shouldn't have console.log("here") or console.log(user) scattered everywhere. Here's how to build logging that actually helps when things break.

Use a Logging Library

// Bad
console.log("User created:", user);
console.log("Error:", err);

// Good (using Winston)
const winston = require('winston');

const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'app.log' })
    ]
});

logger.info('User created', { userId: user.id, email: user.email });
logger.error('Failed to create user', { error: err.message, stack: err.stack });
Enter fullscreen mode Exit fullscreen mode

Log Levels

error  → Something broke. Needs immediate attention.
warn   → Something unexpected but handled. Worth investigating.
info   → Normal operations. "User logged in", "Order processed".
debug  → Development details. Request payloads, intermediate values.
Enter fullscreen mode Exit fullscreen mode

In production: LOG_LEVEL=info. In development: LOG_LEVEL=debug.

Structured Logging

// Bad: unstructured text
logger.info(`User ${userId} placed order ${orderId} for $${total}`);

// Good: structured JSON
logger.info('Order placed', {
    userId,
    orderId,
    total,
    items: order.items.length
});
Enter fullscreen mode Exit fullscreen mode

Structured logs are searchable. You can query:

  • "Show all logs where userId=123"
  • "Show all orders where total > 1000"

Text logs require regex parsing.

Request Logging Middleware

const { v4: uuid } = require('uuid');

app.use((req, res, next) => {
    req.requestId = uuid();
    const start = Date.now();

    res.on('finish', () => {
        logger.info('Request completed', {
            requestId: req.requestId,
            method: req.method,
            path: req.path,
            statusCode: res.statusCode,
            duration: Date.now() - start,
            userAgent: req.get('user-agent'),
            ip: req.ip
        });
    });

    next();
});
Enter fullscreen mode Exit fullscreen mode

What to Log

// DO log:
logger.info('Payment processed', { orderId, amount, provider: 'stripe' });
logger.warn('Rate limit approaching', { userId, current: 95, limit: 100 });
logger.error('Database connection failed', { host, retryIn: '5s' });

// DON'T log:
logger.info('Entering function processOrder');  // Noise
logger.debug(req.body);  // May contain passwords
logger.info(`User password: ${user.password}`);  // Never log secrets
Enter fullscreen mode Exit fullscreen mode

Log Rotation

// Winston with rotation
const DailyRotateFile = require('winston-daily-rotate-file');

const transport = new DailyRotateFile({
    filename: 'logs/app-%DATE%.log',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '14d'  // Keep 14 days
});
Enter fullscreen mode Exit fullscreen mode

Without rotation, log files grow until they fill your disk.

The Golden Rule

Log as if the person reading it is debugging a production incident at 3 AM, has never seen the code, and the only context they have is what's in the log.


What logging setup do you use? Any tools you'd recommend?

Top comments (0)