0

我的 nodejs / Express js 后端正在使用Winston记录器。

src/utils/logger.ts

import winston from 'winston'
import moment from 'moment';
import os from 'os';
import process from 'process';
import request from 'express';


const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
}

const level = () => {
  return 'debug'
}

const colors = {
  error: 'red',
  warn: 'yellow',
  info: 'green',
  http: 'magenta',
  debug: 'white',
}
winston.addColors(colors)

const timezonedTime = () => {
  return moment().local().format('YYYY-MMM-DD hh:mm:ss:ms');  
}; 
   

const format_string = winston.format.combine(
  winston.format.timestamp({format: timezonedTime}),
  winston.format.colorize({ all: true }),
  winston.format.printf(
    (info) => `${info.timestamp}  ${os.hostname()} ${process.pid} ${info.level}: ${info.message}`,
  ),
)

const format_json = winston.format.combine(
  winston.format.timestamp({format: timezonedTime}),
  winston.format.colorize({ all: true }),
  winston.format.printf(
    (info) => `${info.timestamp}  ${os.hostname()} ${process.pid} ${info.level}: ${info.message}`,
  ),
  winston.format.json(),
)


const options = {
  conosle: {
    format: format_string,
    level: 'info',
    handleExceptions: true,
    json: false,
    colorize: true,
  },

  error_logfile: {
    filename: 'logs/error.log',
    level: 'error',
    format: format_string,
    handleExceptions: true,
  }, 

  all_logfile: { 
    filename: 'logs/all.log', 
    format: format_string 
  },

  all_logfile_json: { 
    filename: 'logs/all_json.log',
    format: format_json
  }

};

const transports = [
  new winston.transports.Console(options.conosle),
  new winston.transports.File(options.error_logfile),
  new winston.transports.File(options.all_logfile),
  new winston.transports.File(options.all_logfile_json),
]

const Logger = winston.createLogger({
  level: level(),
  levels,
  transports,
})

export default Logger


我的应用程序设计为只要用户登录了他的帐户,请求标头就会包含一个username字段。

我想将它username放入由 api 端点中的函数引起的每条日志消息中。现在我正在做:

/src/routes.ts:

app.get('/api/organizations/project', organizations.getProject); 

和:

export const getProject = catchErrors( async (req, res) => {

  const username = req.header('username');
  if (!username) {
    Logger.warn(`no req.headers.username found!`);
    throw new NoUsernameError();
  }


  const user = await findUserWithOrganizationsByUsername(username);
  const userId = user.id; 
  const userType = user.userType; 
  Logger.info(`User ${req.headers.username} has id and type ${userId}, ${userType};`);


  const organizationId = req.query.organizationId; 
  
  const organization = await findEntityOrThrow(Organization, organizationId, {
    relations: ['users']
  });

  Logger.info(`User ${req.headers.username}:  got organization`);


  ...

基本上在业务逻辑代码的许多步骤中,我需要在其中记录一条消息,req.headers.username就像在所有日志条目中一样。leveltimestamp

有没有一种优雅的方式来放置它?我不想做

Logger.info(`User ${req.headers.username}  ....bla bla bla ... `);

在每个记录器行中。

4

1 回答 1

1

要为每个日志事件添加一些内容defaultMeta(来自Winston 文档):

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  defaultMeta: { service: 'user-service' },
  transports: [
    //
    // - Write all logs with importance level of `error` or less to `error.log`
    // - Write all logs with importance level of `info` or less to `combined.log`
    //
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
  ],
});

要将附加上下文添加到日志事件的子集,请使用子记录器

const childLogger = logger.child({ requestId: '451' });
childLogger.info('This log will have an attached requestId');
于 2022-02-02T08:27:42.567 回答