Author: saqibkhan

  • Performance Optimization

    Logging can impact performance. Here are some tips:

    • Asynchronous Logging: Use async transports to avoid blocking the main thread.
    class AsyncTransport extends winston.TransportStreamOptions { log(info, callback) { setImmediate(() => this.emit('logged', info)); setTimeout(() => { console.log(${info.level}: ${info.message}); if (callback) callback(); }, 100); } }
    • Batching Logs: Collect logs and send them in batches to reduce I/O operations.
    • Log Rotation and Compression: Use log rotation and compression to manage disk usage.
  • Dynamic Log Levels

    You might need to adjust log levels dynamically, for example, via an environment variable or a configuration file.

    const winston = require('winston');
    
    const logLevel = process.env.LOG_LEVEL || 'info';
    
    const logger = winston.createLogger({
      level: logLevel,
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ), transports: [
    new winston.transports.Console()
    ] }); logger.info('This log level is dynamically set');
  • Logging Middleware for Express

    In an Express application, you can create middleware to log HTTP requests and responses.

    const express = require('express');
    const winston = require('winston');
    
    const app = express();
    
    const logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ), transports: [
    new winston.transports.Console()
    ] }); app.use((req, res, next) => { logger.info('HTTP Request', {
    method: req.method,
    url: req.url,
    headers: req.headers
    }); res.on('finish', () => {
    logger.info('HTTP Response', {
      statusCode: res.statusCode,
      statusMessage: res.statusMessage
    });
    }); next(); }); app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
  • Integrating with APM Tools

    Application Performance Management (APM) tools like New Relic, Datadog, or Dynatrace can be used alongside Winston for enhanced monitoring.

    • Datadog Integration:
    npm install winston-datadog
    const winston = require('winston'); const DatadogTransport = require('winston-datadog'); const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new DatadogTransport({ apiKey: 'YOUR_DATADOG_API_KEY', hostname: 'my-hostname' }) ] }); logger.info('Log sent to Datadog');
  • Log Aggregation

    For aggregating logs from multiple sources, you can use tools like Fluentd, Logstash, or Graylog. Here’s how you might configure Winston to send logs to Fluentd:

    npm install winston-fluentd
    

    Then set up the transport:

    const winston = require('winston');
    const FluentTransport = require('winston-fluentd');
    
    const logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ), transports: [
    new FluentTransport({
      host: 'localhost',
      port: 24224,
      timeout: 3.0,
      tag: 'app.log'
    })
    ] }); logger.info('Log sent to Fluentd');
  • Structured Logging

    Structured logging involves logging in a format that makes it easy to search and analyze logs. JSON is a common structured logging format.

    const winston = require('winston');
    
    const logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ), transports: [
    new winston.transports.Console()
    ] }); logger.info('User login', { userId: 123, username: 'john_doe' });

    Structured logs are easy to query and analyze with tools like Elasticsearch, Kibana, or log aggregators.

  • Asynchronous Logging

    Winston supports asynchronous logging by using promises or callbacks in custom transports. Here’s an example using promises:

    const { TransportStreamOptions } = require('winston-transport');
    
    class AsyncTransport extends TransportStreamOptions {
      constructor(options) {
    
    super(options);
    } async log(info) {
    return new Promise((resolve, reject) => {
      setImmediate(() => this.emit('logged', info));
      // Simulate async operation
      setTimeout(() => {
        console.log(Async log: ${info.level}: ${info.message});
        resolve();
      }, 1000);
    });
    } } const logger = winston.createLogger({ level: 'info', transports: [
    new AsyncTransport()
    ] }); logger.info('This is an async log message');
  • Querying Logs

    If you’re logging to a database or an external service, querying logs can be useful. For instance, with MongoDB and winston-mongodb, you can query logs like this:

    const winston = require('winston');
    require('winston-mongodb');
    
    const logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ), transports: [
    new winston.transports.MongoDB({
      db: 'mongodb://localhost/logs',
      collection: 'log',
      level: 'info'
    })
    ] }); // Querying logs from MongoDB const MongoClient = require('mongodb').MongoClient; MongoClient.connect('mongodb://localhost/logs', function (err, client) { if (err) throw err; const db = client.db('logs'); const collection = db.collection('log'); collection.find({ level: 'info' }).toArray(function (err, docs) {
    if (err) throw err;
    console.log(docs);
    client.close();
    }); });
  • Log Rotation

    For managing log file sizes and rotation, you can use the winston-daily-rotate-file transport. Install it first:

    npm install winston-daily-rotate-file
    

    Then configure it like so:

    const winston = require('winston');
    require('winston-daily-rotate-file');
    
    const transport = new winston.transports.DailyRotateFile({
      filename: 'application-%DATE%.log',
      datePattern: 'YYYY-MM-DD',
      maxSize: '20m',
      maxFiles: '14d',
      level: 'info',
      format: winston.format.combine(
    
    winston.format.timestamp(),
    winston.format.json()
    ) }); const logger = winston.createLogger({ level: 'info', transports: [transport] }); logger.info('This message will be logged to a daily rotated file');
  • Custom Transports

    Winston supports creating custom transports to log messages in unique ways. Here’s a basic example of a custom transport:

    const { TransportStreamOptions } = require('winston-transport');
    
    class CustomTransport extends TransportStreamOptions {
      constructor(options) {
    
    super(options);
    this.level = options.level || 'info';
    } log(info, callback) {
    setImmediate(() => this.emit('logged', info));
    console.log(${info.level}: ${info.message});
    if (callback) callback();
    } } const logger = winston.createLogger({ level: 'info', format: winston.format.simple(), transports: [
    new CustomTransport({ level: 'info' })
    ] }); logger.info('This is a custom transport log message');