winstonjs / winston

A logger for just about everything.
http://github.com/winstonjs/winston
MIT License
22.87k stars 1.81k forks source link

format.errors not working on transport level #1880

Open mrdulin opened 3 years ago

mrdulin commented 3 years ago

Please tell us about your environment:

When I use format.errors({stack: true}) on logger configuration level, it works as expected. The logger parses JavaScript Error object and prints correctly.

import { createLogger, format, transports } from 'winston';

const logFormatter = format.printf((info) => {
  let { timestamp, level, stack, message } = info;
  message = stack || message;
  return `${timestamp} ${level}: ${message}`;
});

const logToConsole = createLogger({
  level: 'info',
  format: format.errors({ stack: true }),
  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), format.simple(), format.timestamp(), logFormatter),
    }),
  ],
});

const err = new Error('network');
logToConsole.error(err);

Output:

2021-01-22T06:55:25.500Z error: Error: network
    at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/65822479/index.ts:19:13)
    at Module._compile (internal/modules/cjs/loader.js:1158:30)
    at Module.m._compile (/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/node_modules/ts-node/src/index.ts:858:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/node_modules/ts-node/src/index.ts:861:12)
    at Module.load (internal/modules/cjs/loader.js:1002:32)
    at Function.Module._load (internal/modules/cjs/loader.js:901:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at main (/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/node_modules/ts-node/src/bin.ts:227:14)
    at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/node_modules/ts-node/src/bin.ts:513:3)

I think the format.errors({ stack: true }) can be used on transport level too. But it doesn't.

import { createLogger, format, transports } from 'winston';

const logFormatter = format.printf((info) => {
  let { timestamp, level, stack, message } = info;
  message = stack || message;
  return `${timestamp} ${level}: ${message}`;
});

const logToConsole = createLogger({
  level: 'info',
  // format: format.errors({ stack: true }),
  transports: [
    new transports.Console({
      format: format.combine(
        format.errors({ stack: true }),
        format.colorize(),
        format.simple(),
        format.timestamp(),
        logFormatter,
      ),
    }),
  ],
});

const err = new Error('network');
logToConsole.error(err);

Output:

2021-01-22T06:58:00.582Z error: undefined

What do you expect to happen instead?

I think the configuration of the logger level is a global configuration, and the configuration of the transport level is the configuration for each transport, and has the highest priority, covering the global configuration.

They are should have the same output.

tniezg commented 3 years ago

Setting handleExceptions: true in the transport's options helps, but the error stack is lost. It's mentioned that exceptions are broken in Winston 3: https://github.com/winstonjs/winston/blob/master/examples/exception.js. This issue only happens when the error is provided directly as an argument. When the value of message is an error then the error is provided to transports' formatters.

borel commented 3 years ago

I open a MR about this subject to handle format type at transporter level

OktarinTentakel commented 3 years ago

Any news on this?

MinusFour commented 2 years ago

The winston-transport module "clones" the info object being formatted:

https://github.com/winstonjs/winston-transport/blob/e4a6ce1a0b788d4fe56b4be94c30a3bebe96c2e2/index.js#L90-L94

This leads to only copying enumerable properties, which on Error objects not even message is. So the object itself is pretty much blank at that point (at the very least devoid of any Error properties).

Since the error formatter is expecting an Error (or at least an error object inside a message property) it does nothing.

An alternative that could work as it is right now:

logToConsole.error({
   message: err
});

Which I guess you can monkey patch on the class instance.

const logError = logToConsole.error.bind(logToConsole);
logToConsole.error = (message) => logError({ message });

I'll just point out that the log formatter (that is, the one that's on the logger itself) does not receive a copy of an object but the object itself.

deyayan commented 2 years ago

In my use case, I found that setting errors: true globally interferes with exception logging in a separate file. It turns out that if the option is enabled, undefined gets logged if logging in a separate file. https://github.com/winstonjs/winston/issues/2195