npm package: @sonatel-os/juf-xpress-logger
Description: Structured, secure Node.js logger with automatic sensitive data masking, ECS JSON format, colorized console output, Elastic APM tracing, and Winston transport — production-ready audit logging for Express APIs
Author: Mohamed Johnson
Latest version: 1.0.0

<div align="center">

# 🔐 XPress Logger

**Structured, secure, colorized logging for Node.js services.**

Built for production. Hardened by default. ECS-compliant out of the box.

[![npm version](https://img.shields.io/npm/v/@sonatel-os/juf-xpress-logger?color=cc3534&label=npm)](https://www.npmjs.com/package/@sonatel-os/juf-xpress-logger)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Node](https://img.shields.io/badge/node-%3E%3D16-brightgreen)](https://nodejs.org)
[![Elastic ECS](https://img.shields.io/badge/format-ECS%208.10-00bfb3)](https://www.elastic.co/guide/en/ecs/current/index.html)

</div>

---

## ⚡ Why XPress Logger?

Most loggers give you text lines. XPress Logger gives you **structured, ECS-compliant JSON** with automatic **sensitive data masking**, **colorized terminal output**, and **Elastic APM tracing** — all wired together in one `bootstrap()` call.

| Feature | Description |
|---------|-------------|
| 🛡️ **Auto-masking** | Passwords, tokens, cookies — masked recursively, even in nested JSON strings |
| 🎨 **Colorized output** | Key fields light up in your terminal — level, method, status, path, action |
| 📊 **ECS format** | Every log is Elastic Common Schema compliant — ready for Kibana, no transforms needed |
| 🔍 **APM integration** | Elastic APM transactions, spans, and trace correlation built in |
| ⚙️ **Zero config** | Sane defaults. One import, one `bootstrap()`, you're logging |
| 🔑 **Exceptional decrypt** | Conditionally bypass masking for specific methods, headers, or body patterns |

---

## 🚀 Quick Start

```bash
# Yarn
yarn add @sonatel-os/juf-xpress-logger

# npm
npm install @sonatel-os/juf-xpress-logger
```

```javascript
import { logger } from '@sonatel-os/juf-xpress-logger';

// 1. Bootstrap once at app startup
logger.bootstrap({
  appName: 'my-api',
  crypt: ['password', 'ssn', 'credit_card'],
});

// 2. Log structured events
logger.writeLog({
  params: {
    logFrom: req.ip,
    userIp: req.headers['x-forwarded-for'],
    method: req.method,
    payload: req.body,
    headers: req.headers,
    logTarget: req.path,
    userAgent: req.headers['user-agent'],
    logStatus: res.statusCode,
    logStatusCode: res.statusMessage,
  },
  userName: req.user?.email,
  logLevel: 'INFO',
  action: 'User authentication',
  duration: Date.now() - startTime,
});
```

**Output** — single-line ECS JSON with colorized fields in terminal:

```
{"@timestamp":"2026-03-08T12:17:49Z","log.level":"info","message":{"event.action":"User authentication","http.request.method":"POST","http.request.body.content":{"username":"john","password":"***************"},"http.response.status_code":200,"url.path":"/api/login",...}}
```

> 🎨 In your terminal: `log.level` glows **cyan**, `event.action` is **green**, `http.request.method` is **blue**, status codes shift **green → yellow → red** by range, and `url.path` pops in **cyan**.

---

## 🔧 API Reference

### `logger.bootstrap(config)`

Initializes the logger. **Must be called once before any other method.**

```javascript
logger.bootstrap({
  appName: 'my-api',             // Log identification (default: 'app')
  crypt: ['ssn', 'credit_card'], // Keys to mask (merged with built-in defaults)
  logConsole: true,               // Log to console (default: true)
  logLevel: 'info',              // APM log level (default: 'info')
  startApmAgent: false,          // Start Elastic APM agent (default: false)
  exceptionalDecrypt: {          // Conditions to bypass masking
    method: 'GET',               // Skip masking for GET requests
    headers: { 'x-internal': 'true' },
    body: { type: 'public' },
  },
});
```

**Built-in masked keys** (always active, case-insensitive):
`password` · `pass` · `confirmpassword` · `authorization` · `client_id` · `client_secret` · `cookie` · `content-secured` · `captcha`

Returns the `LoggerService` instance for chaining.

---

### `logger.writeLog(options)`

Writes a structured, ECS-compliant audit log entry.

```javascript
logger.writeLog({
  params: {
    logFrom: '192.168.1.1',      // Origin IP
    userIp: '10.0.0.1',          // User IP
    method: 'POST',              // HTTP method
    payload: req.body,           // Request body (object or JSON string)
    headers: req.headers,        // Request headers (object or JSON string)
    logTarget: '/api/users',     // Target URL path
    userAgent: 'Mozilla/5.0',   // User-Agent string
    logStatus: 201,              // HTTP status code
    logStatusCode: 'Created',    // HTTP status message
  },
  userName: 'admin@company.com', // Who (default: 'anonymousUser')
  logLevel: 'INFO',              // Level: INFO, WARN, ERROR (default: 'INFO')
  action: 'Created new user',   // What happened
  duration: 142,                 // How long (ms, optional)
});
```

---

### `logger.captureApmMiddleware(config)`

Express/Connect middleware for Elastic APM transaction capture.

> Requires APM env vars: `JUF_ELK_APM_SERVER`, `JUF_ELK_APM_ENV_NAME`, `JUF_ELK_APM_SERVICE_NAME`, `JUF_ELK_APM_SECRET_TOKEN`

```javascript
app.use((req, res, next) => {
  logger.captureApmMiddleware({
    params: {
      path: req.path,
      method: req.method,
      headers: req.headers,
      routeParams: req.params,
      queryParams: req.query,
      payload: req.body,
    },
    callback: next,
    httpListener: {
      onFunction: res.on.bind(res),
      callback: () => {},
    },
  });
});
```

---

### `logger.transactionSpans`

Fine-grained APM span tracing for specific operations.

```javascript
// Start a span
const span = logger.transactionSpans.begin({
  name: 'Redis cache lookup',
  type: 'cache',
  payload: { key: 'user:42' },
});

const result = await redis.get('user:42');

// End the span
logger.transactionSpans.end(span);
```

| Method | Description |
|--------|-------------|
| `.begin({ name, type?, payload? })` | Starts a span. Returns the span object or `null`. |
| `.end(span)` | Ends the span and records its duration. |

---

## 🛡️ Security

XPress Logger is designed with a **security-first** mindset:

- **Recursive masking** — Sensitive keys are masked at any depth, including inside JSON strings
- **Case-insensitive** — `Authorization`, `AUTHORIZATION`, `authorization` are all caught
- **Default deny** — 9 common sensitive keys are masked without any configuration
- **Headers always masked** — Even when `exceptionalDecrypt` bypasses payload masking, headers are always sanitized
- **No secret logging** — The mask value (`***************`) reveals nothing about the original value's length

---

## 🔄 Comparisons

| | XPress Logger | winston | pino | bunyan |
|---|:---:|:---:|:---:|:---:|
| ECS format out of the box | ✅ | ❌ | ❌ | ❌ |
| Auto sensitive data masking | ✅ | ❌ | ❌ | ❌ |
| Elastic APM integration | ✅ | ❌ | ❌ | ❌ |
| Colorized JSON fields | ✅ | ❌ | ❌ | ❌ |
| Zero-config defaults | ✅ | ❌ | ✅ | ❌ |
| Express middleware | ✅ | ❌ | ✅ | ❌ |
| Audit logging | ✅ | ❌ | ❌ | ❌ |

---

## 📄 License

MIT License. See [LICENSE](./LICENSE) for details.

---

<div align="center">

Built with 🧡 by [Mohamed Johnson](https://github.com/lpix-11) · Part of the [@sonatel-os](https://www.npmjs.com/settings/sonatel-os/packages) ecosystem

**Node.js logging** · **Express logger** · **Structured JSON logging** · **ECS logging** · **Audit logging** · **Data masking** · **Elastic APM** · **Kibana-ready logs**

</div>