ryankurte / winston-cluster

Winston transport for Node.js clustering
MIT License
7 stars 5 forks source link

Linked Transports #26

Open phuze opened 1 year ago

phuze commented 1 year ago

Is there a way to link a winstonCluster() transport, to a specific parent logger?

My scenario is a little niche -- effectively I need two loggers in order to be able to define separate hostnames for my syslog transports.

If I log something:

process.loggerOne.info('Hello world')

it ends up being sent to the parent process and subsequently logged twice, because I am binding both loggers to the child worker. I am trying to log exclusively to one logger, or the other, depending on which I used:

process.loggerOne.info('My name is John')
process.loggerTwo.info('My name is Sarah')

results in:

HOST-1 APP-1: My name is John
HOST-2 APP-2: My name is John
HOST-1 APP-1: My name is Sarah
HOST-2 APP-2: My name is Sarah

whereas my desired outcome would be:

HOST-1 APP-1: My name is John
HOST-2 APP-2: My name is Sarah

Here's my current setup (less any irrelevant bits of code):

const cluster = require('cluster')
const os = require('os')
const winston = require('winston')
const winstonCluster = require('winston-cluster')
require('winston-syslog')

// master
if (cluster.isMaster) {

  // logger 1
  const loggerOne = winston.createLogger({
    transports: [
      new winston.transports.Syslog({
        host: 'logs9.papertrailapp.com',
        port: 99999,
        localhost: 'HOST-1',
        appName: 'APP-1',
      })
    ]
  })

  // logger 2
  const loggerTwo = winston.createLogger({
    transports: [
      new winston.transports.Syslog({
        host: 'logs9.papertrailapp.com',
        port: 99999,
        localhost: 'HOST-2',
        appName: 'APP-2',
      })
    ]
  })

  // fork workers
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork()
  }

  // when a new worker is started, bind our loggers
  cluster.on('online', (worker) => {
    winstonCluster.bindListener(worker, loggerOne)
    winstonCluster.bindListener(worker, loggerTwo)
  })
}

// worker
else {

  // inject logger 1 into process
  process.loggerOne = winston.createLogger({
    transports: [
      new winstonCluster({})
    ]
  })

  // inject logger 2 into process
  process.loggerTwo = winston.createLogger({
    transports: [
      new winstonCluster({})
    ]
  })
}
phuze commented 1 year ago

As an update, I've discovered a workaround using winston filters.

By applying a filter to each parent logger, I can achieve the desired effect. Example:

// logger 1
const loggerOne = winston.createLogger({
  format: winston.format.combine(
    winston.format((message) => {
      if (message.foo) { return false; }
      return message;
    })()
  ),
  transports: [
    new winston.transports.Syslog({
      host: 'logs9.papertrailapp.com',
      port: 99999,
      localhost: 'HOST-1',
      appName: 'APP-1',
    })
  ]
})

// logger 2
const loggerTwo = winston.createLogger({
  format: winston.format.combine(
    winston.format((message) => {
      if (!message.foo) { return false; }
      return message;
    })()
  ),
  transports: [
    new winston.transports.Syslog({
      host: 'logs9.papertrailapp.com',
      port: 99999,
      localhost: 'HOST-2',
      appName: 'APP-2',
    })
  ]
})

Unfortunately, it means logging gets a little messy:

process.loggerOne.info('My name is John')

process.loggerTwo.log({
  foo: true,
  level: 'info',
  message: 'My name is Sarah'
})

Would still like to know if it's possible to link/bind a winstonCluster() transport, to a specific parent logger?