npm package: @rexp/logger
Description: A comprehensive Winston-based logger with request correlation, data redaction, structured logging helpers, and Express middleware for Node.js microservices
Latest version: 2.1.0

# @rexp/logger

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

[![npm version](https://img.shields.io/npm/v/@rexp/logger.svg)](https://www.npmjs.com/package/@rexp/logger)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

## 📋 Table of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage Guide](#usage-guide)
  - [Basic Logging](#basic-logging)
  - [Express Middleware](#express-middleware)
  - [Structured Logging Helpers](#structured-logging-helpers)
  - [Specialized Loggers](#specialized-loggers)
  - [Request Correlation](#request-correlation)
  - [Data Redaction](#data-redaction)
  - [File Logging & Rotation](#file-logging--rotation)
- [API Reference](#api-reference)
- [Examples](#examples)
- [Troubleshooting](#troubleshooting)
- [License](#license)

## ✨ 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

```bash
npm install @rexp/logger
```

```javascript
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)

```bash
npm install @rexp/logger
```

### With File Rotation Support

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

### For CI/CD Pipelines

```bash
# 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

```bash
# 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

```javascript
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:

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

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

logAudit(
  "user_update", // Action
  adminUserId, // Who performed the action
  "users/user123", // Resource affected
  {
    oldValue: { email: "old@example.com" },
    newValue: { email: "new@example.com" },
    ip: "192.168.1.1",
    success: true,
  }
);
```

#### 🌐 API Request Logging

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
logger.info("User data", {
  username: "john_doe",
  password: "secret123", // Will be redacted
  email: "john@example.com",
  token: "abc123", // Will be redacted
});

// Output:
// {
//   username: 'john_doe',
//   password: '***REDACTED***',
//   email: 'john@example.com',
//   token: '***REDACTED***'
// }
```

Add custom redaction fields:

```bash
LOG_REDACT_FIELDS=email,phone,ssn,creditCard
```

### Child Loggers

Create child loggers with persistent context:

```javascript
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):

```javascript
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:

```bash
# .env file
LOG_FILE_ENABLED=true
LOG_DIR=/var/log/myapp
LOG_MAX_SIZE=50m
LOG_MAX_FILES=30d
LOG_ZIP_ARCHIVES=true
```

```bash
# 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

```javascript
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

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

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

### Microservice Example

```javascript
// 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:

```bash
npm install winston-daily-rotate-file
```

And set the environment variable:

```bash
LOG_FILE_ENABLED=true
```

### Issue: Logs not appearing

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

```bash
# Show all logs
LOG_LEVEL=debug

# Production (info and above)
LOG_LEVEL=info
```

### Issue: Correlation ID not appearing

**Solution:** Use the `requestLogger()` middleware:

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

### Issue: Sensitive data appearing in logs

**Solution:** Add fields to redaction list:

```bash
LOG_REDACT_FIELDS=email,phone,customField
```

### Issue: Wrong IP address in logs

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

```javascript
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](LICENSE) file for details.

## 🔗 Links

- [GitHub Repository](https://github.com/reXPapp/rexp-logger-npm)
- [npm Package](https://www.npmjs.com/package/@rexp/logger)
- [Report Issues](https://github.com/reXPapp/rexp-logger-npm/issues)

---

Made with ❤️ for the Node.js community