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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@heavybit/logger-ts

v1.0.0

Published

A comprehensive TypeScript logging package for Express.js with AOP support, request/response logging middleware, stdout and file logging

Downloads

184

Readme

@pesalink/logger-ts

A comprehensive TypeScript logging package for Express.js applications with AOP (Aspect-Oriented Programming) support, request/response logging middleware, stdout and file logging based on environment configuration.

Features

  • 🚀 TypeScript First: Full TypeScript support with comprehensive type definitions
  • 📝 Winston-based: Built on the robust Winston logging library
  • 🔄 Dual Output: Log to stdout (console), files, or both based on configuration
  • 🗂️ Log Rotation: Automatic daily log rotation with compression
  • 🎯 AOP Logging: Aspect-oriented programming support with decorators and utilities
  • 🛡️ Data Sanitization: Automatic redaction of sensitive fields (passwords, tokens, etc.)
  • 🏷️ Class-based Log Levels: Different log levels for controllers, services, repositories, etc.
  • 🔧 Environment Config: Full configuration via environment variables
  • 🧩 Express Middleware: Ready-to-use logging middleware for Express.js
  • 📊 Structured Logging: JSON-formatted logs for easy parsing and analysis

Installation

npm install @pesalink/logger-ts

# Peer dependency
npm install express

Quick Start

Basic Usage

import express from 'express';
import { initLogger, getLogger, loggingMiddleware } from '@pesalink/logger-ts';

const app = express();

// Initialize logger (reads from environment variables)
const logger = initLogger();

// Add middleware
app.use(express.json());
app.use(loggingMiddleware);

// Use the logger
app.get('/api/users', async (req, res) => {
  logger.info('Fetching users');
  res.json({ users: [] });
});

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

Custom Configuration

import { initLogger, LoggerConfig } from '@pesalink/logger-ts';

const config: Partial<LoggerConfig> = {
  target: 'both', // 'stdout' | 'file' | 'both'
  defaultLevel: 'debug',
  appName: 'my-service',
  console: {
    colorize: true,
    level: 'debug',
  },
  file: {
    directory: 'logs',
    maxSize: '100m',
    maxFiles: '30d',
    zippedArchive: true,
    datePattern: 'YYYY-MM-DD',
    level: 'info',
  },
  classLevels: {
    controllers: 'info',
    services: 'debug',
    repositories: 'error',
  },
  sensitiveFields: ['customSecret'], // Additional fields to redact
};

const logger = initLogger(config);

Environment Variables

# Log target: 'stdout', 'file', or 'both'
LOG_TARGET=both

# Default log level
LOG_LEVEL=debug

# Console configuration
LOG_COLORIZE=true

# File configuration
LOG_DIR=logs
LOG_MAX_SIZE=50m
LOG_MAX_FILES=30d
LOG_DATE_PATTERN=YYYY-MM-DD
LOG_ZIPPED_ARCHIVE=true

# Class-specific log levels
LOG_LEVEL_CONTROLLERS=info
LOG_LEVEL_SERVICES=debug
LOG_LEVEL_REPOSITORIES=error
LOG_LEVEL_UTILS=warn
LOG_LEVEL_MIDDLEWARE=info
LOG_LEVEL_ROUTES=info

# Application info
APP_NAME=my-app
NODE_ENV=development
HEALTHCHECK_ENDPOINT=/health

API Reference

Logger Functions

initLogger(config?: Partial<LoggerConfig>): ExtendedLogger

Initialize the logger singleton. Call once at application startup.

const logger = initLogger({
  target: 'both',
  defaultLevel: 'info',
});

getLogger(): ExtendedLogger

Get the logger instance (creates default if not initialized).

const logger = getLogger();
logger.info('Hello world');
logger.error('An error occurred', { error: err.message });

createLogger(config?: Partial<LoggerConfig>): ExtendedLogger

Create a new logger instance with custom config (does not replace singleton).

const customLogger = createLogger({
  target: 'file',
  file: { directory: 'custom-logs' },
});

Logging Methods

const logger = getLogger();

// Standard Winston methods
logger.error('Error message', { metadata: 'value' });
logger.warn('Warning message');
logger.info('Info message');
logger.debug('Debug message');
logger.verbose('Verbose message');

// Extended methods
logger.logWithMeta('info', 'Message', { custom: 'data' });
logger.logRequest({
  message: 'Request completed',
  method: 'GET',
  url: '/api/users',
  statusCode: 200,
  responseTime: '50ms',
});

Middleware

loggingMiddleware

Default logging middleware with standard configuration.

app.use(loggingMiddleware);

createLoggingMiddleware(options: MiddlewareOptions)

Create custom logging middleware.

app.use(createLoggingMiddleware({
  skipEndpoints: ['/health', '/metrics'],
  logRequestBody: true,
  logResponseBody: false,
  requestIdGenerator: () => uuid(),
  additionalFields: (req) => ({
    userId: req.user?.id,
  }),
}));

errorLoggingMiddleware

Error logging middleware for Express error handling.

app.use(errorLoggingMiddleware);

morganStyleMiddleware(format)

Morgan-style request logging.

app.use(morganStyleMiddleware('dev')); // 'combined' | 'common' | 'dev' | 'short' | 'tiny'

AOP (Aspect-Oriented Programming)

Using Decorators

import { LogClass, LogMethod } from '@pesalink/logger-ts';

@LogClass(['constructor'], ['getAll']) // Exclude constructor, only log errors for getAll
class UserController {
  async getAll(req, res) {
    // Only errors will be logged
  }

  @LogMethod('UserController', 'create', 'around', 'controllers')
  async create(req, res) {
    // Full before/after logging
  }
}

Using logMethodsWithAOP

import { logMethodsWithAOP } from '@pesalink/logger-ts';

class ProductService {
  async getAll(req, res) { /* ... */ }
  async create(req, res) { /* ... */ }
}

logMethodsWithAOP(
  ProductService.prototype,
  ['constructor'],        // Excluded methods
  ['getAll'],             // Only log errors for these
  'ProductService',       // Class name
  'services',             // Class type
  'around'                // Advice type
);

Using withLogging Wrapper

import { withLogging } from '@pesalink/logger-ts';

const handler = async (req, res) => {
  res.json({ data: [] });
};

app.get('/api/items', withLogging(handler, 'getItems', 'ItemController'));

Using wrapRoutesWithLogging

import { Router } from 'express';
import { wrapRoutesWithLogging } from '@pesalink/logger-ts';

const router = Router();

router.get('/', handler1);
router.post('/', handler2);

// Wrap all routes in the router
wrapRoutesWithLogging(router, 'ApiRouter', 'routes', ['GET /']);

app.use('/api', router);

Sanitization

import { sanitizeData, sanitizeHeaders, prepareForLogging } from '@pesalink/logger-ts';

// Sanitize object (redacts sensitive fields)
const safe = sanitizeData({
  username: 'john',
  password: 'secret123', // -> [REDACTED]
  token: 'abc123',       // -> [REDACTED]
});

// Sanitize headers
const safeHeaders = sanitizeHeaders(req.headers);

// Prepare for logging with truncation
const truncated = prepareForLogging(largeObject, {
  truncateLength: 1000,
});

Configuration Functions

import {
  initConfig,
  getConfig,
  resetConfig,
  getLogLevelForClass,
} from '@pesalink/logger-ts';

// Initialize configuration
initConfig({ target: 'both' });

// Get current config
const config = getConfig();

// Get log level for a class type
const level = getLogLevelForClass(config, 'controllers'); // 'info'

// Reset configuration (useful for testing)
resetConfig();

Log Output Format

Console (Structured)

2024-01-15T10:30:45.123+0000 | app=my-service | className=UserController | OperationName=getUser | Method=GET | Endpoint=/api/users/1 | LogLevel=info | Payload={} | Message=Request completed | RequestId=abc-123 | ResponseTime=45ms | StatusCode=200

File (JSON)

{
  "timestamp": "2024-01-15T10:30:45.123+0000",
  "level": "info",
  "app": "my-service",
  "environment": "production",
  "className": "UserController",
  "methodName": "getUser",
  "method": "GET",
  "url": "/api/users/1",
  "requestId": "abc-123",
  "statusCode": 200,
  "responseTime": "45ms",
  "message": "Request completed"
}

Log Files

When file logging is enabled, logs are stored in the configured directory with the following structure:

logs/
├── 2024-01-15.log        # All logs for the day
├── 2024-01-15-error.log  # Error-only logs
├── 2024-01-14.log.gz     # Compressed archived logs
└── 2024-01-14-error.log.gz

Best Practices

1. Initialize Early

// At the top of your entry file
import { initLogger } from '@pesalink/logger-ts';
const logger = initLogger();

2. Use Appropriate Log Levels

logger.error('Database connection failed', { error: err.message }); // Errors
logger.warn('Rate limit approaching', { current: 90, max: 100 });   // Warnings
logger.info('User logged in', { userId: '123' });                    // Info
logger.debug('Cache hit', { key: 'user:123' });                      // Debug

3. Include Context

logger.info('Processing payment', {
  transactionId: 'txn-123',
  userId: 'user-456',
  amount: 100.00,
  currency: 'USD',
});

4. Handle Errors Properly

try {
  await riskyOperation();
} catch (error) {
  logger.error('Operation failed', {
    error: error.message,
    stack: error.stack,
    context: { operationId: '123' },
  });
  throw error;
}

5. Use Class-Specific Levels

Configure verbose logging for debugging specific layers:

LOG_LEVEL_SERVICES=debug
LOG_LEVEL_REPOSITORIES=error  # Only log database errors

Examples

See the examples/ directory for complete examples:

TypeScript Support

All types are exported from the package:

import type {
  LoggerConfig,
  LogLevel,
  ClassType,
  LogTarget,
  ExtendedLogger,
  RequestLogEntry,
  AOPContext,
  MiddlewareOptions,
} from '@pesalink/logger-ts';

License

MIT

Author

Nicholas Kute