Winston: Transports and v2 to v3 migration

Created on 25 May 2018  Â·  5Comments  Â·  Source: winstonjs/winston

Hi 👋!

With the 3.0 release coming, I am trying to get a sense for what the expectation is for Transport authors to deal with the new release. We are getting feature requests for winston@3 support already on our transport.

Looking at the upgrade guide it seems like there are significant enough API changes that I don't see an easy way to support both winston@2 and winston@3 out of the same transport package. Is the expectation that Transport authors would be releasing a new set of packages for winston@3 (e.g. winston-funky-transport vs. winston3-funky-transport). Alternatively do we need to maintain two semver major branches concurrently on for winston@2 and one for winston@3? Both of those options sound unappetizing to me.

I can imagine some shenanigans where we try to require winston dynamically to see what the user actually has available and then expose a different version depending of the precise version? That is way too hacky, and something we can't to do in our Transport – as we are a TypeScript project and want the users to have predictable usable types.

It is possible I am either overthinking it, or perhaps I am missing something. If the project authors here have thoughts on this, it would be great to have some feedback on what the vision about the Transport migration path is.

Thanks a lot!

/cc @MylesBorins @DominicKramer

docs important

All 5 comments

That's a great question. There is no silver bullet here, sorry. A TL;DR for a possible approach goes something like:

  1. Upgrade your transport to the winston@3 API.
  2. Write a wrapper to your winston@3 transport that exposes a winston@2 API, e.g.:
// winston@3 symbols
// https://github.com/winstonjs/winston#streams-objectmode-and-info-objects
const { MESSAGE, LEVEL } = require('triple-beam'); 

// The `winston@3` transport you wrote in (1) above.
const winston3Transport = require('./your-winston3-transport');

module.exports = class YourLegacyTransport {
  constructor(opts) {
    this.transport = new winston3Transport(opts);
  }

  log(level, msg, meta, callback) {
    this.transport.log(Object.assign({}, meta, { 
      level, 
      message,
      MESSAGE: message,
      LEVEL: level 
    }, callback);
  }
}
  1. Expose that as require('your-transport/legacy');
  2. Document it.
  3. Done.

Of course this would not work seamlessly, but it would easy enough to document this generically or throw in some console warnings if they are using winston@2 with your winston@3 transport, e.g.:

const Transport = require('winston-transport');

module.exports = class YourWinston3Transport extends Transport {
  log(info, callback) {
    if (arguments.length > 2) throw new Error(```
You appear to be using [email protected]
Please use require('winston-your-transport/legacy');
```);
  }

  /* your transport code continues below */
}

Regardless of the approach it's not a silver bullet is that in winston@2 every Transport had to implement their own formatting options, nothing was shareable between them. Most transport just called common.log (which is still available in winston-compat for exactly this kind of interop) from winston, so _for the 80%+_ they can just invoke that and pass the resultant object to the winston@3 transport for serialization. If you defined your own formatting options however, you'll have to reimplement those as formats.

_Would love a PR to the upgrade guide to explain this in detail to transport authors!_ 😸

In winston-daily-rotate-file, I used a check using semver to determine which version was in use and then defined the appropriate methods depending on the result.

Base class decision: https://github.com/winstonjs/winston-daily-rotate-file/blob/293d7fe6b79408b0f10b129a1726e375e6f39821/daily-rotate-file.js#L13

Log method declaration: https://github.com/winstonjs/winston-daily-rotate-file/blob/293d7fe6b79408b0f10b129a1726e375e6f39821/daily-rotate-file.js#L114-L136

My thinking on this is that, while it somewhat complicates the transport code, it allows callers to use either winston@2 or winston@3 without any changes.

That's a very interesting technique @mattberther! Thanks for sharing.

Is this going anywhere, particularly in regards to https://github.com/googleapis/nodejs-logging-winston/issues/84

@vongohren, see this PR, explicitly for Winston@3. Could use help on the two failing test cases.

Was this page helpful?
0 / 5 - 0 ratings