Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Splat and error stack traces do not work when used in conjunction #2527

Open
codemedian opened this issue Nov 13, 2024 · 0 comments
Open

Comments

@codemedian
Copy link

codemedian commented Nov 13, 2024

🔎 Search Terms

splat, stack trace, error

The problem

I've just started using winston recently and so far quite like the way it works. The biggest problem for me right now is that I can't use splat in conjunction with errors in a way that makes sense. The below snippet showcases the issue I face

try {
  new Error("something weng wrong")
} catch (error) {
    log.error("OOps", error); // ==> logs an error stack trace as expected
    log.error("Oops %d", 1, error);   //==> drops the error altogether and doesn't log it
}

I have tried quite a few variations of formatter configurations and the formatter never (regradless of using splat or not) gets the error and stacktrace in a way that is usable in the printf formatter, or to add into json.

For reference, the logger setup looks as follows

winston.configure({
  transports: [
    new winston.transports.Console({
      handleExceptions: true,
    }),
  ],
  format: winston.format.combine(
    winston.format.errors({ stack: true }),
    winston.format.timestamp(),
    winston.format.splat(),
    winston.format.json(),
  ),
  level: process.env.LOG_LEVEL ?? "info",
});

I have now hacked something that does the trick for me by intercepting the log and putting the stack into it's own object if an error is encountered (at the last position). This works then with the above logger setup using splat and json/printf formats

const warnAndErrorStackTraceIntercept: LeveledLogMethod = (
  message: any,
  ...meta: any[]
) => {
  if (message instanceof Error) {
    winston.log("error", message.message, { stack: message.stack });
  } else if (meta[meta.length - 1] instanceof Error) {
    const error = meta.pop();
    winston.log("error", message, ...meta, { stack: error.stack });
  } else {
    winston.log("error", message, ...meta);
  }
  return winston as unknown as Logger;
};
winston.error.prototype = warnAndErrorStackTraceIntercept;
winston.warn.prototype = warnAndErrorStackTraceIntercept;

const originalWinstonChild = winston.child;
winston.child = (options) => {
  let logger = originalWinstonChild(options);
  logger.error = warnAndErrorStackTraceIntercept;
  logger.warn = warnAndErrorStackTraceIntercept;
  return logger;
};

What version of Winston presents the issue?

v3.17.0

What version of Node are you using?

v20.17.0

If this worked in a previous version of Winston, which was it?

No response

Minimum Working Example

import winston, { LeveledLogMethod, Logger } from "winston";

const Colors: { [level: string]: string } = {
  info: "\x1b[32m",
  error: "\x1b[31m",
  warn: "\x1b[33m",
  verbose: "\x1b[36m",
  debug: "\x1b[36m",
};

winston.configure({
  transports: [
    new winston.transports.Console({
      handleExceptions: true,
    }),
  ],
  format: winston.format.combine(
    winston.format.errors({ stack: true }),
    winston.format.timestamp(),
    winston.format.splat(),
    process.env.LOG_FORMAT === "json"
      ? winston.format.json()
      : winston.format.printf((info) => {
          const { level, message, label, timestamp, ...meta } = info;
          const { component, stack, ...extra } = meta;
          return `${Colors[level]}${timestamp} [${level.toUpperCase()}] ${component ?? "default"}\x1b[0m - ${message}${extra && Object.keys(extra).length > 0 ? ` \x1b[35m - ${JSON.stringify(extra)}\x1b[0m` : ""}${stack ? "\n" + stack : ""}`;
        }),
  ),
  level: process.env.LOG_LEVEL ?? "info",
});


try {
  new Error("something weng wrong")
} catch (error) {
    winston.error("Oops", error); // ==> logs an error stack trace as expected
    winstonerror("Oops %d", 1, error);   //==> drops the error altogether and doesn't log it
}

Additional information

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant