npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rexp/logger

v2.1.0

Published

A comprehensive Winston-based logger with request correlation, data redaction, structured logging helpers, and Express middleware for Node.js microservices

Readme

@rexp/logger

A comprehensive Winston-based logger with request correlation, data redaction, structured logging helpers, and Express middleware for Node.js microservices.

npm version License: MIT

📋 Table of Contents

✨ Features

  • 🚀 Winston-based - Built on the industry-standard Winston logger
  • 🔗 Request Correlation - Automatic correlation ID tracking across requests
  • 🔒 Auto Redaction - Sensitive data automatically redacted from logs
  • 🎨 Colorized Output - Beautiful console logs in development
  • 📝 Structured Helpers - Pre-built helpers for common logging scenarios
  • 🌐 Cloud-Ready - EKS/Kubernetes-compatible IP extraction
  • 🔐 Specialized Loggers - Dedicated security and audit loggers
  • 📦 Express Middleware - Drop-in middleware for Express apps
  • 🔄 File Rotation - Optional daily log rotation with compression
  • 💪 Error Resilient - Fallback mechanisms prevent logging failures
  • 🎯 Zero Config - Works out of the box with sensible defaults

🚀 Quick Start

npm install @rexp/logger
const express = require("express");
const logger = require("@rexp/logger");
const { requestLogger } = require("@rexp/logger/src/middleware");

const app = express();
app.use(requestLogger());

app.get("/", (req, res) => {
  logger.info("Hello from @rexp/logger!");
  res.json({ message: "Hello, World!" });
});

app.listen(3000, () => {
  logger.info("Server running on port 3000");
});

📦 Installation

Basic Installation (Console Logging Only)

npm install @rexp/logger

With File Rotation Support

npm install @rexp/logger winston-daily-rotate-file

For CI/CD Pipelines

# Install with optional dependencies
npm ci --include=optional

# Install without optional dependencies (console only)
npm ci --omit=optional

⚙️ Configuration

Configure the logger using environment variables:

Core Configuration

| Variable | Default | Description | | ----------------- | ----------------------------- | --------------------------------------------------- | | SERVICE_NAME | unknown-service | Your service/application name | | SERVICE_VERSION | 0.0.0 | Your service version | | NODE_ENV | development | Environment (development/production) | | LOG_LEVEL | debug (dev) / info (prod) | Log level: silly, debug, verbose, info, warn, error | | LOG_PRETTY | false | Enable pretty-printed logs (good for development) |

Data Redaction

| Variable | Default | Description | | ------------------- | ------- | ------------------------------------------------------ | | LOG_REDACT_FIELDS | - | Comma-separated fields to redact (e.g., email,phone) |

Default redacted fields: password, pass, token, otp, secret, ssn

File Logging (Requires winston-daily-rotate-file)

| Variable | Default | Description | | ------------------ | -------- | --------------------------------- | | LOG_FILE_ENABLED | false | Enable file logging | | LOG_DIR | ./logs | Directory for log files | | LOG_MAX_SIZE | 20m | Max file size before rotation | | LOG_MAX_FILES | 14d | Retention period (e.g., 14d, 30d) | | LOG_ZIP_ARCHIVES | true | Compress rotated log files |

Example .env File

# Service Info
SERVICE_NAME=auth-service
SERVICE_VERSION=1.2.0
NODE_ENV=production

# Logging
LOG_LEVEL=info
LOG_PRETTY=false
LOG_REDACT_FIELDS=email,phone,creditCard

# File Logging
LOG_FILE_ENABLED=true
LOG_DIR=/var/log/app
LOG_MAX_SIZE=50m
LOG_MAX_FILES=30d
LOG_ZIP_ARCHIVES=true

📖 Usage Guide

Basic Logging

const logger = require("@rexp/logger");

// Different log levels
logger.silly("Very detailed debug info");
logger.debug("Debug information");
logger.verbose("Verbose information");
logger.info("General information");
logger.warn("Warning messages");
logger.error("Error messages");

// With metadata
logger.info("User logged in", {
  userId: "user123",
  ip: "192.168.1.1",
  timestamp: new Date().toISOString(),
});

// Error with stack trace
try {
  throw new Error("Something went wrong");
} catch (error) {
  logger.error("An error occurred", {
    error: error.message,
    stack: error.stack,
  });
}

Express Middleware

Request Logger Middleware

Automatically logs all incoming requests with correlation IDs:

const express = require("express");
const { requestLogger } = require("@rexp/logger/src/middleware");

const app = express();
app.use(requestLogger());

app.get("/api/users", (req, res) => {
  // All logs in this request will include the correlation ID
  res.json({ users: [] });
});

HTTP Request Logging

const logger = require("@rexp/logger");

logger.http(req, res, { customField: "value" });
// Automatically logs with appropriate level based on status code

Structured Logging Helpers

Pre-built functions for common logging scenarios:

🔐 Authentication Logging

const { logAuth } = require("@rexp/logger");

// Successful login
logAuth(
  "user_login",
  userId,
  {
    success: true,
    ip: "192.168.1.1",
    userAgent: req.get("User-Agent"),
  },
  req
);

// Failed login
logAuth(
  "login_failed",
  userId,
  {
    success: false,
    reason: "Invalid password",
    ip: "192.168.1.1",
  },
  req
);

🛡️ Authorization Logging

const { logAuthz } = require("@rexp/logger");

logAuthz(
  "resource_access",
  userId, // User ID
  "/api/admin/users", // Resource
  "read", // Action
  true, // Granted (true/false)
  { ip: "192.168.1.1" }, // Additional details
  req // Request object (optional)
);

🚨 Security Incident Logging

const { logSecurityIncident } = require("@rexp/logger");

logSecurityIncident(
  "brute_force_attempt", // Incident type
  "high", // Severity: low, medium, high, critical
  "Multiple failed login attempts", // Description
  {
    userId: "user123",
    ip: "192.168.1.1",
    attemptCount: 5,
  }
);

📊 Audit Logging

const { logAudit } = require("@rexp/logger");

logAudit(
  "user_update", // Action
  adminUserId, // Who performed the action
  "users/user123", // Resource affected
  {
    oldValue: { email: "[email protected]" },
    newValue: { email: "[email protected]" },
    ip: "192.168.1.1",
    success: true,
  }
);

🌐 API Request Logging

const { logApiRequest } = require("@rexp/logger");

logApiRequest({
  method: "POST",
  url: "/api/users",
  statusCode: 201,
  responseTime: 45, // milliseconds
  userId: userId,
  req: req, // For automatic IP extraction
});

💾 Database Operation Logging

const { logDbOperation } = require("@rexp/logger");

logDbOperation(
  "INSERT", // Operation: INSERT, UPDATE, DELETE, SELECT
  "users", // Table name
  userId, // User ID
  {
    recordsAffected: 1,
    query: "INSERT INTO users...",
    success: true,
  }
);

📁 File Operation Logging

const { logFileOperation } = require("@rexp/logger");

logFileOperation(
  "upload", // Operation: upload, download, delete
  "document.pdf", // Filename
  userId, // User ID
  {
    fileSize: 1024000,
    mimeType: "application/pdf",
    path: "/uploads/document.pdf",
    success: true,
  }
);

🖥️ System Event Logging

const { logSystemEvent } = require("@rexp/logger");

logSystemEvent(
  "database_connected", // Event type
  "database", // Component
  {
    message: "Connected to PostgreSQL",
    data: { host: "localhost", port: 5432 },
  }
);

🌍 HTTP Request Logging with Timing

const { logHttpRequest } = require("@rexp/logger");

app.use((req, res, next) => {
  const start = Date.now();
  res.on("finish", () => {
    const responseTime = Date.now() - start;
    logHttpRequest(req, res, responseTime);
  });
  next();
});

Specialized Loggers

Dedicated loggers for specific use cases:

const { securityLogger, auditLogger } = require("@rexp/logger");

// Security events (automatically categorized)
securityLogger.warn("Suspicious activity detected", {
  userId: "user123",
  ip: "192.168.1.1",
  pattern: "rapid_requests",
});

// Audit events (automatically categorized)
auditLogger.info("Configuration changed", {
  userId: "admin123",
  setting: "max_upload_size",
  oldValue: "10MB",
  newValue: "50MB",
});

Request Correlation

Correlation IDs automatically track requests across your application:

const { runWithContext } = require("@rexp/logger/src/context");

// Manual context creation
runWithContext({ correlationId: "custom-id", userId: "user123" }, () => {
  logger.info("This log will include the correlation ID");
  // All logs within this context will include correlationId and userId
});

// The requestLogger middleware handles this automatically for Express apps

Data Redaction

Sensitive fields are automatically redacted:

logger.info("User data", {
  username: "john_doe",
  password: "secret123", // Will be redacted
  email: "[email protected]",
  token: "abc123", // Will be redacted
});

// Output:
// {
//   username: 'john_doe',
//   password: '***REDACTED***',
//   email: '[email protected]',
//   token: '***REDACTED***'
// }

Add custom redaction fields:

LOG_REDACT_FIELDS=email,phone,ssn,creditCard

Child Loggers

Create child loggers with persistent context:

const logger = require("@rexp/logger");

// Create child logger with context
const userLogger = logger.child({
  userId: "user123",
  module: "user-service",
});

userLogger.info("User action performed");
// All logs will include userId and module

const orderLogger = logger.child({
  orderId: "order456",
  module: "order-service",
});

orderLogger.info("Order created");
// All logs will include orderId and module

IP Extraction (Cloud-Ready)

Extract real client IP from requests (handles load balancers, proxies, EKS, Kubernetes):

const { extractClientIP } = require("@rexp/logger");

app.use((req, res, next) => {
  const clientIP = extractClientIP(req);
  console.log("Real client IP:", clientIP);

  // Automatically handles headers from:
  // - x-forwarded-for (most common)
  // - x-real-ip (Nginx)
  // - x-client-ip (Apache)
  // - cf-connecting-ip (Cloudflare)
  // - x-cluster-client-ip (Kubernetes)
  // - and more...

  next();
});

File Logging & Rotation

Enable file logging with automatic rotation:

# .env file
LOG_FILE_ENABLED=true
LOG_DIR=/var/log/myapp
LOG_MAX_SIZE=50m
LOG_MAX_FILES=30d
LOG_ZIP_ARCHIVES=true
# Install rotation package
npm install winston-daily-rotate-file

Log files will be organized like this:

/var/log/myapp/
  ├── application-2025-10-14.log      # Today's log
  ├── application-2025-10-13.log.gz   # Yesterday (compressed)
  ├── application-2025-10-12.log.gz
  └── ...

Features:

  • ✅ Daily rotation (new file each day)
  • ✅ Size-based rotation (when file exceeds max size)
  • ✅ Automatic compression (.gz)
  • ✅ Retention policy (auto-delete old logs)
  • ✅ Event monitoring (rotate, archive, logRemoved)

📚 API Reference

Core Logger Methods

| Method | Description | | -------------------------------- | ---------------------------------- | | logger.silly(message, meta?) | Silly level logs (lowest priority) | | logger.debug(message, meta?) | Debug information | | logger.verbose(message, meta?) | Verbose information | | logger.info(message, meta?) | General information | | logger.warn(message, meta?) | Warning messages | | logger.error(message, meta?) | Error messages (highest priority) | | logger.child(fields) | Create child logger with context | | logger.http(req, res, extra?) | Log HTTP request/response |

Structured Logging Helpers

| Function | Parameters | Description | | ------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------- | | logAuth(event, userId, details, req?) | event, userId, details, request | Log authentication events | | logAuthz(event, userId, resource, action, granted, details, req?) | event, userId, resource, action, granted, details, request | Log authorization events | | logSecurityIncident(type, severity, description, details) | type, severity, description, details | Log security incidents | | logAudit(action, userId, resource, details) | action, userId, resource, details | Log audit trail | | logApiRequest(options) | options object | Log API requests | | logDbOperation(operation, table, userId, details) | operation, table, userId, details | Log database operations | | logFileOperation(operation, filename, userId, details) | operation, filename, userId, details | Log file operations | | logSystemEvent(event, component, details) | event, component, details | Log system events | | logHttpRequest(req, res, responseTime) | request, response, responseTime | Log HTTP requests with timing |

Utilities

| Function | Parameters | Returns | Description | | ----------------------------- | ----------------- | ---------- | -------------------------------------- | | extractClientIP(req) | request | string | Extract real client IP from request | | requestLogger() | - | middleware | Express middleware for request logging | | runWithContext(context, fn) | context, function | any | Run function within logging context | | getContext() | - | object | Get current logging context |

Specialized Loggers

| Logger | Description | | ---------------- | -------------------------------------- | | securityLogger | Logger with security category | | auditLogger | Logger with audit category | | logHelpers | Object containing all helper functions |

💡 Examples

Complete Express App Example

const express = require("express");
const logger = require("@rexp/logger");
const { requestLogger } = require("@rexp/logger/src/middleware");
const { logAuth, logSecurityIncident, extractClientIP } = logger;

const app = express();
app.use(express.json());
app.use(requestLogger());

// Login endpoint with authentication logging
app.post("/login", (req, res) => {
  const { username, password } = req.body;

  if (password === "correct") {
    logAuth(
      "user_login",
      username,
      {
        success: true,
        userAgent: req.get("User-Agent"),
      },
      req
    );

    res.json({ success: true, token: "jwt-token" });
  } else {
    logAuth(
      "login_failed",
      username,
      {
        success: false,
        reason: "Invalid password",
      },
      req
    );

    logSecurityIncident(
      "failed_login_attempt",
      "medium",
      "Failed login detected",
      {
        username,
        ip: extractClientIP(req),
      }
    );

    res.status(401).json({ error: "Invalid credentials" });
  }
});

// Protected route with authorization
app.get("/admin/users", (req, res) => {
  const userId = req.user?.id || "anonymous";
  const isAdmin = req.user?.role === "admin";

  logger.logAuthz(
    "resource_access",
    userId,
    "/admin/users",
    "read",
    isAdmin,
    {},
    req
  );

  if (!isAdmin) {
    return res.status(403).json({ error: "Forbidden" });
  }

  res.json({ users: [] });
});

// Error handling
app.use((err, req, res, next) => {
  logger.error("Application error", {
    error: err.message,
    stack: err.stack,
    url: req.url,
    method: req.method,
  });

  res.status(500).json({ error: "Internal server error" });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  logger.logSystemEvent("server_started", "api-server", {
    message: `Server started on port ${PORT}`,
    data: { port: PORT, env: process.env.NODE_ENV },
  });
});

Morgan Integration

const morgan = require("morgan");
const logger = require("@rexp/logger");

// Use logger.stream with Morgan
app.use(morgan("combined", { stream: logger.stream }));

Microservice Example

// service-a/index.js
const logger = require("@rexp/logger");

async function processOrder(orderId) {
  const orderLogger = logger.child({ orderId, service: "order-processor" });

  orderLogger.info("Processing order");

  try {
    // Business logic
    orderLogger.debug("Validating order");

    orderLogger.logDbOperation("SELECT", "orders", "system", {
      recordsAffected: 1,
      success: true,
    });

    orderLogger.info("Order processed successfully");
  } catch (error) {
    orderLogger.error("Order processing failed", {
      error: error.message,
      stack: error.stack,
    });
    throw error;
  }
}

🔧 Troubleshooting

Issue: File logging not working

Solution: Ensure winston-daily-rotate-file is installed:

npm install winston-daily-rotate-file

And set the environment variable:

LOG_FILE_ENABLED=true

Issue: Logs not appearing

Solution: Check your LOG_LEVEL setting. If set to error, only error logs will appear.

# Show all logs
LOG_LEVEL=debug

# Production (info and above)
LOG_LEVEL=info

Issue: Correlation ID not appearing

Solution: Use the requestLogger() middleware:

const { requestLogger } = require("@rexp/logger/src/middleware");
app.use(requestLogger());

Issue: Sensitive data appearing in logs

Solution: Add fields to redaction list:

LOG_REDACT_FIELDS=email,phone,customField

Issue: Wrong IP address in logs

Solution: Use the extractClientIP function which handles load balancers and proxies:

const { extractClientIP } = require("@rexp/logger");
const clientIP = extractClientIP(req);

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🔗 Links


Made with ❤️ for the Node.js community