NodeJS Winston日志对象

6gpjuf90  于 2023-05-22  发布在  Node.js
关注(0)|答案(7)|浏览(156)

我使用Winston作为我的后端日志记录,如果不使用JSON.stringify,我就无法记录对象,这很烦人

logger.debug(`Register ${JSON.stringify(req.body)}`)
const logger: Logger = createLogger({
    // change level if in dev environment versus production
    level: env === 'production' ? 'info' : 'debug',
    format: format.combine(
        format.label({label: path.basename(process.mainModule.filename)}),
        format.timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
        format.prettyPrint()
    ),
    transports: [
        new transports.Console({
            format: format.combine(format.colorize(), logFormat),
        }),
        new transports.File({
            filename,
            format: format.combine(format.json()),
        }),
    ],
    exitOnError: false,
})

你能告诉我用Winston登录对象的方法吗?我用的是3.2.1版

nhhxz33t

nhhxz33t1#

您尝试将JSON对象直接插入到字符串中,因此它将打印不带JSON.stringify[Object Object]
这个问题不能通过配置Winston来解决,因为这个问题发生在字符串生成时(在logger.debug函数实际读取它之前),所以console.log调用将打印相同的内容。
logger.*函数的第一个参数是message(字符串),然后可以传递一个元数据对象(JSON)。
要在logFormat函数中使用元数据,请按以下方式更新Logger示例:

const winston = require('winston')
const { format, transports } = winston
const path = require('path')

const logFormat = format.printf(info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`)

const logger = winston.createLogger({
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
  format: format.combine(
    format.label({ label: path.basename(process.mainModule.filename) }),
    format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    // Format the metadata object
    format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] })
  ),
  transports: [
    new transports.Console({
      format: format.combine(
        format.colorize(),
        logFormat
      )
    }),
    new transports.File({
      filename: 'logs/combined.log',
      format: format.combine(
        // Render in one line in your log file.
        // If you use prettyPrint() here it will be really
        // difficult to exploit your logs files afterwards.
        format.json()
      )
    })
  ],
  exitOnError: false
})

使用方法:

const req = {
  body: {
    name: 'Daniel Duuch',
    email: 'daniel.duuch@greatmail.com',
    password: 'myGreatPassword'
  }
}

logger.debug(`Register ${req.body.name} with email ${req.body.email}`, { ...req.body, action: 'register' })

控制台输出:

2019-05-11 17:05:45 debug [index.js]: Register Daniel Duuch with email daniel.duuch@greatmail.com

日志文件输出(手工美化,参见传输文件格式中的注解):

{
  message: 'Register Daniel Duuch with email daniel.duuch@greatmail.com',
  level: 'debug',
  timestamp: '2019-05-11 17:05:45',
  label: 'index.js',
  metadata: {
    name: 'Daniel Duuch',
    email: 'daniel.duuch@greatmail.com',
    password: 'myGreatPassword',
    action: 'register'
  }
}

希望这能解决你的问题。

重要提示:正如@Xetera在评论中指出的那样,“你应该确保你没有在任何地方记录人们的密码”

Code for this answer

ca1c2owp

ca1c2owp2#

您可以在日志记录器配置中使用format.splat()

const logger = createLogger({
    format: combine(
        ...
        format.splat(), // <--
        ...
    ),
    ...
});

...和使用字符串插值的日志对象:

let myObj = { /* ... */ };
logger.info('This message will include a complete object: %O', myObj);
5cnsuln7

5cnsuln73#

我的解决方案是使用这种格式化程序:

const { format } = winston
const consoleFormat = format.combine(
  format.prettyPrint(),
  format.splat(),
  format.printf((info) => {
    if (typeof info.message === 'object') {
      info.message = JSON.stringify(info.message, null, 3)
    }

    return info.message
  })
)

现在所有这些选项都按预期工作:

logger.info('plain text')
logger.info('plain text with object %o', { a:1, b: 2} )
logger.info({ a:1, b: 2 })
kx5bkwkv

kx5bkwkv4#

我不得不合并@SherloxFR和@Anton提供的解决方案。

const Winston = require('winston');
const { format } = Winston;

const options = {
    file: {
        ....
        format: format.combine(
            format.splat(), 
            format.json()
        ),
        ...
    },
    console: {
        ...
        format: format.combine(
            format.splat(),
            format.json()
        ),
        ...
    }
};

您可以看到我在上面的代码中将format.splat()format.json()添加到选项配置中。

const logger = new Winston.createLogger({
    transports: [
        new Winston.transports.File(options.file),
        new Winston.transports.Console(options.console)
    ],
    exitOnError: false // do not exit on handled exceptions
});

这就是我如何使用选项配置对象。你可以在transports数组中编写格式代码,但我不喜欢这种方式。反正这是你的选择。
在这样的配置之后,就是我在代码中使用它的方式

let myObj = {
   name: "StackOverflow",
};

logger.info('Content: %o', myObj);

如果你愿意,你也可以这样传播它

logger.info('Content: %o', {...myObj});

就是这样。Winston应该用这个设置记录你的对象。

hm2xizp9

hm2xizp95#

如果您希望将对象记录到控制台和文件,可以执行以下操作:
1.初始化2种格式。一个用于文件,另一个用于控制台。注意consoleFormat中使用的JSON.stringify方法

const winston = require("winston");
const { format, transports, createLogger } = winston;
const path = require("path");
const consoleloggerLevel = process.env.WINSTON_LOGGER_LEVEL || "info";

const consoleFormat = format.combine(
  format.colorize(),
  format.timestamp(),
  format.align(),
  format.printf((info) => {
    return `${info.timestamp} - ${info.level}:  [${info.label}]: ${
      info.message
    } ${JSON.stringify(info.metadata)}`;
  })
);

const fileFormat = format.combine(
  format.timestamp(),
  format.label({ label: path.basename(process.mainModule.filename) }),
  format.metadata({ fillExcept: ["message", "level", "timestamp", "label"] }),
  format.json()
);

2.现在,创建记录器。

const logger = createLogger({
  level: "info",
  defaultMeta: { service: "some-random-service" },
  format: fileFormat,
  transports: [
    new transports.File({
      filename: path.join(__dirname, "../logs/error.log"),
      level: "error",
    }),
    new transports.File({
      filename: path.join(__dirname, "../logs/activity.log"),
      maxsize: 5242880, //5MB
      maxFiles: 5 // just in case  
    }),
  ],
});

3.仅在非生产环境中启用控制台日志记录:

if (process.env.NODE_ENV !== "production") {
  logger.add(
    new transports.Console({
      level: consoleloggerLevel,
      format: consoleFormat,
    })
  );
}

4.将其导出为默认记录器

module.exports = logger;

关于logger.info("Server started listening", { port: 9000 } );
这个会打印出来

  • 在控制台上:*
2021-06-22T07:47:25.988Z - info:  [index.js]:   Server started listening {"service":"some-random-service", "port": 9000}
  • 在文件中:*
{"message":"Server started listening","level":"info","timestamp":"2021-06-22T07:47:25.988Z","label":"index.js","metadata":{"service":"some-random-service", "port": 9000}}
9gm1akwq

9gm1akwq6#

或者你就用
printf
函数与JSON.stringify配合使用

new winston.transports.Console({
  format: winston.format.combine(
    winston.format.colorize(),
    winston.format.simple(),
    winston.format.printf(context => {
      const msgstr = JSON.stringify(context.message, null, '\t')
      return `[${context.level}]${msgstr}`
    }),
  ),
})
k5ifujac

k5ifujac7#

winston-pretty将以一种强大而通用的方式解决这个问题。这是一个独立的程序,它将winston json log作为输入,并输出人类可读的日志行。它还可以打印json和错误。

npm install -g winston-pretty

npm run <your-project> | winston-pretty

https://www.npmjs.com/package/winston-pretty

相关问题