Skip to content

Introduction to Backend Logging Patterns

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Introduction to Backend Logging Patterns. We cover key concepts, practical examples, and best practices to help you master this topic.

Logging is the practice of recording events from an application for debugging, monitoring, auditing, and analysis. Effective logging provides observability into system behavior, helps diagnose production issues, and enables security auditing and compliance reporting.

flowchart LR
    App[Application] --> Logger[Logger Library]
    Logger -->|Stdout| Collector[Log Collector - Filebeat/Fluentd]
    Logger -->|JSON| Console[Console Output]
    Collector --> Aggregator[Log Aggregator - ELK/Loki]
    Aggregator --> Storage[(Elasticsearch/Loki)]
    Storage --> Dashboard[Grafana/Kibana]
    Storage --> Alert[Alerting]
    Storage --> Search[Log Search]

What You'll Learn

  • Structured vs. unstructured logging
  • Log levels (error, warn, info, debug, trace)
  • Winston and Pino logger configuration
  • Centralized log aggregation with ELK stack

Why It Matters

Without logging, debugging production issues is like operating blind. Good logging reduces mean time to resolution (MTTR) from hours to minutes. Poor logging (or too much logging) creates noise that obscures real problems.

Real-World Use

A microservice platform uses structured JSON logging with correlation IDs. When an error occurs, the operations team searches by correlation ID to see the complete request trace across all services. They identify the failing service in under 30 seconds.

Logging Implementation

Structured Logging with Winston

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { service: 'user-service' },
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      )
    }),
    new winston.transports.File({
      filename: 'logs/error.log',
      level: 'error',
      maxsize: 52428800,
      maxFiles: 5
    }),
    new winston.transports.File({
      filename: 'logs/combined.log',
      maxsize: 52428800,
      maxFiles: 5
    })
  ]
});

Expected output:

{"level":"info","message":"Server started","service":"user-service","timestamp":"2026-06-28T10:00:00.000Z"}

Logging Middleware with Correlation ID

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

function loggingMiddleware(req, res, next) {
  const correlationId = req.headers['x-correlation-id'] || uuidv4();
  req.correlationId = correlationId;

  const start = Date.now();

  res.on('finish', () => {
    const duration = Date.now() - start;
    logger.info('request completed', {
      correlationId,
      method: req.method,
      url: req.originalUrl,
      status: res.statusCode,
      duration: `${duration}ms`,
      userAgent: req.headers['user-agent'],
      ip: req.ip
    });
  });

  next();
}

Expected output:

{"level":"info","message":"request completed","correlationId":"abc-123","method":"GET","url":"/api/users","status":200,"duration":"45ms"}

Pino Logger (High Performance)

const pino = require('pino');

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  transport: {
    target: 'pino-pretty',
    options: { colorize: true, translateTime: true }
  },
  redact: ['req.headers.authorization', 'req.body.password', 'req.body.ssn'],
  serializers: {
    req: pino.stdSerializers.req,
    res: pino.stdSerializers.res,
    err: pino.stdSerializers.err
  }
});

app.use(require('pino-http')({ logger }));

// Usage
app.get('/api/users', async (req, res) => {
  logger.info({ userId: req.user.id }, 'Fetching user profile');
  const user = await db.getUser(req.params.id);
  res.json(user);
});

Expected output:

[10:00:00.000] INFO: Fetching user profile
    userId: "123"
Sensitive fields in headers/body are redacted automatically.

Common Mistakes

  • Logging sensitive data (passwords, tokens, PII) in plaintext — always redact or mask.
  • Using unstructured logs (plain text) instead of structured (JSON) — structured logs are machine-parseable and searchable.
  • Logging too much (debug in production) — too many logs create noise and increase costs.
  • Logging too little (no error context) — "Something went wrong" without stack trace or context is useless.
  • Not including correlation IDs — without correlation, you cannot trace a request across services.

Practice Questions

  1. What is the difference between structured and unstructured logging?
  2. What log levels should you use and when?
  3. Why is a correlation ID important in Distributed Systems?
  4. How does log redaction protect sensitive data?
  5. What is the difference between Winston and Pino?

Challenge

Set up structured logging for a Node.js API. Implement: (1) Winston logger with JSON format, (2) request logging middleware with correlation ID, (3) error logging with stack traces, (4) sensitive data redaction, (5) different log levels for dev and production.

FAQ

What is structured logging?

Structured logging outputs logs in a structured format (JSON) with named fields. It is machine-parseable and enables searching and filtering in log aggregation systems.

What log level should I use in production?

INFO is the default production level. ERROR for failures, WARN for unexpected but handled issues, INFO for significant events, DEBUG for development only.

Should I log to files or stdout?

In containerized environments, log to stdout/stderr. The container runtime or orchestration platform (Kubernetes) handles log collection. File logging is for non-containerized deployments.

What is log redaction?

Log redaction automatically replaces sensitive data (passwords, tokens, SSNs) with [REDACTED] before writing logs. Pino and Winston support this with configuration.

How do I centralize logs from multiple services?

Use a log shipper (Filebeat, Fluentd) to send logs to a central aggregator (Elasticsearch, Loki). Use Kibana or Grafana for visualization and search.

Mini Project

Build a logging system for a microservice. Implement: (1) Pino logger with JSON output, (2) HTTP request/response logging middleware, (3) correlation ID propagation, (4) sensitive data redaction, (5) error Serialization with stack traces. Send logs to stdout.

What's Next

Continue to Structured Logging for a detailed guide on structured log formats.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro