Sitemap
Nazar Pashazade

Nazar Pashazade

Senior Software Engineer

Tired of Configuring Winston? Read This.

4 min readSep 11, 2025

--

When you’re building a modern Node.js app, here’s the truth:

Logging isn’t optional — it’s everything. Think about it.

  • In development, it helps you debug issues fast.
  • In production, it’s how you track requests across multiple services without tearing your hair out. A good logging setup can literally save you hours, if not days.

While working on microservices, I noticed developers (including myself) often repeated the same steps:

  • Configure Winston with multiple transports
  • Write middleware to log HTTP requests
  • Inject unique requestIds to trace distributed logs
  • Sanitize sensitive fields (password, token, etc.)
  • Pipe logs into Elasticsearch for analysis
  • Maintain consistency across different services

Every project, same boilerplate.

That’s exactly why I built np-express-winston-logger. My goal was simple: create a centralized, type-safe, configurable logger that just works. No more reinventing the wheel every time you spin up a new service.

So, what can it do?

Let me break it down for you:

  • Centralized logger — a single place to handle both application logs and HTTP request logs.
  • Express middleware (httpLogger) — automatically logs every request, with dynamic log levels based on status codes.
  • RequestId injection — every log gets a unique ID, making it easy to trace requests across distributed systems.
  • Sensitive data sanitization — automatically masks passwords, tokens, and any custom fields you specify.
  • Elasticsearch integration — send logs to Elasticsearch for search, visualization, and analysis.
  • Environment-aware logging — adjust behavior depending on whether you’re in dev, prod, stage, or test.
  • TypeScript support — fully typed for IDE autocompletion and fewer errors.

In short, it takes care of all the repetitive, error-prone setup so you can focus on building features instead of debugging your logging system.

Press enter or click to view image in full size

Installation

npm i np-express-winston-logger

# or

yarn add np-express-winston-logger

Your first setup

Here’s what it looks like when you use it in a brand-new Express app:

import express from "express";
import { createLogger } from "np-express-winston-logger";

const { logger, httpLogger } = createLogger({
serviceName: "product-service",
});

const app = express();

// Attach HTTP logger
app.use(httpLogger);

app.get("/", (_req, res) => {
const user = { id: 1, email: "john@example.com", password: "secret" };
logger.info("User:", { user });
res.send("OK");
});

app.listen(3000, () => {
logger.info("Server started successfully");
});

That’s it.

Get Nazar Pashazade’s stories in your inbox

Join Medium for free to get updates from this writer.

Start your app, and you’ll see logs like this in the console:

Notice something?

- password is already masked (sanitized) for you.

2025-09-07T08:41:01.431Z [info] product-service: Server started successfully
2025-09-07T08:20:18.456Z [info] product-service: User: { "id": 1, "email": "john@example.com", "password": "****" }
2025-09-07T08:20:18.457Z [http] product-service: GET / 200 5ms

Want to sanitize custom fields?

By default, fields like password and token are masked. But if you want to add your own, just pass them in:

const { logger } = createLogger({
serviceName: "auth-service",
sanitize: { sensitiveFields: ["email"] },
});

Now email will also be hidden in logs.

Need requestId injection for each request?

import { requestIdMiddleware } from "np-express-winston-logger";
app.use(requestIdMiddleware); // ✅ Make sure requestIdMiddleware comes BEFORE httpLoggerapp.use(httpLogger);

From now on, every log entry will include a reqId, so you can trace logs across your services without manually passing IDs around:

2025-09-07T08:20:18.456Z [info] product-service: [reqId=77d4eb31...] User: { "id": 1, "email": "john@example.com", "password": "****" }
2025-09-07T08:20:18.457Z [http] product-service: [reqId=77d4eb31...] GET / 200 5ms

Need Elasticsearch integration?

Logging to the console is fine, but in production you want logs centralized. That’s where Elasticsearch comes in:

const { logger } = createLogger({
serviceName: "product-service",
elasticsearch: { url: "http://localhost:9200" },
});

Done. Your logs will be searchable, structured, and ready for Kibana dashboards.

Controlling log levels

Not everything deserves to be logged in production. With minLevel, you decide what gets through:

const { logger } = createLogger({
serviceName: "billing-service",
env: "prod",
minLevel: "info", // ignores debug/verbose
});

So logger.debug(...) is ignored in prod, but logger.info(...), logger.warn(...), and logger.error(...) still show up.

When should you use this?

  • You’re building microservices and want consistent logs across all of them
  • You need request-level tracing without writing custom middleware
  • You want to mask sensitive fields automatically
  • You’re sending logs to Elasticsearch (or planning to)

Basically: anytime you don’t want to waste a day configuring Winston by hand.

Summary:

np-express-winston-logger gives you a production-ready logging setup in minutes. No boilerplate, no fragile hacks — just a logger that works the way you expect.

👉 Check the full docs on GitHub

And if it saves you time, I’d love it if you ⭐ the repo and share it with your team.

--