当逗号用作连接运算符时,Winston 不显示文本
Winston not displaying text when comma is used as concatenation operator
我的项目现在正在使用 winston logger 来记录到控制台。问题是,逗号在大多数地区被用作连接运算符,
喜欢logger.info("here is data", data )
数据始终是一个字符串,但记录的只是 "here is data" 而不是其他内容。
项目在大多数地方都使用逗号作为连接符,因此用“+”替换是乏味的。请赞成如何在逗号本身存在的情况下显示数据
你基本上有两种解决方法
1) 手动更改您的 logger.info 函数以获取多个参数,或者编写一个记录器包装器,在传递给 logger.info
之前连接字符串
info = (...args) => {
const data = args.reduce((acc, item) => acc += item);
// or such kind of manual concatenation logic
logger.info(data);
}
2) 使用 es6 模板文字。所以不要使用 logger.info("here is data", data)
,而是使用
logger.info(`here is data ${data}`)
根据 Pressana 的回答,在我的 createLogger
函数中,它负责创建 winston 记录器并将其导出到需要记录的模块,我创建了一个记录器中间件。
这是一个例子
let env;
exports.createLogger = (envP) => {
env = envP;
const logger = winston.createLogger({
level: 'debug',
transports: [
new winston.transports.File({
filename: __dirname + '/error.log',
level: 'error'
}),
new winston.transports.File({
filename: __dirname + '/combined.log'
})
],
'colorize': true
});
const customLogger = getCustomLoggerMiddleware(logger);
if (env !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
return customLogger;
}
function getCustomLoggerMiddleware(logger) {
const customLogger = {};
customLogger.error = reduceLogger(logger.error)
customLogger.warn = reduceLogger(logger.warn)
customLogger.info = reduceLogger(logger.info)
customLogger.http = reduceLogger(logger.http)
customLogger.verbose = reduceLogger(logger.verbose)
customLogger.debug = reduceLogger(logger.debug)
customLogger.silly = reduceLogger(logger.silly)
return customLogger;
}
function reduceLogger(loggerFun) {
return (...args) => {
const data = args.reduce((acc, item) => acc += item);
loggerFun(data);
}
}
createLogger
函数是一个普通的 winston logger 构建器,魔法发生在 getCustomLoggerMiddleware
扩展 Mauricio 的回答是另一种观点。
区别在于它还记录了数组、对象(包括循环)。
logger.jsm
const path = require('path');
const winston = require('winston');
const safeStringify = require('fast-safe-stringify'); // comes with winston
const logger = (forceDev) => {
//
const DEVELOPMENT = forceDev || (process.env.NODE_ENV === 'development');
const logger = winston.createLogger({
level: (DEVELOPMENT) ? 'silly' : 'info',
levels: winston.config.npm.levels,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.align(),
winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
),
transports: DEVELOPMENT
? [
// Output logs to console
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
winston.format.align(),
winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
)
})
]
: [
// Write all logs to files
// With level `error` and below to `error.log`
new winston.transports.File({
filename: path.join(__dirname, '../logs/winston-error.log'),
level: 'error'
}),
// With level `info` and below to `combined.log`
new winston.transports.File({
filename: path.join(__dirname, '../logs/winston-combined.log')
})
]
});
process.on('unhandledRejection', (error) => {
logger.error(error.stack);
});
process.on('uncaughtException', (error) => {
logger.error(error.stack);
});
const wrapperFcn = (orgFcn, ...args) => {
orgFcn(
args
// .filter((arg) => arg !== 'whatever') // custom filter
.reduce((previous, current) => {
const replacer = null;
const space = null;
return `${previous} ${(typeof current === 'string' || current instanceof String) ? current : safeStringify(current, replacer, space)}`;
}, '')
);
};
const getWrappedLogger = (loggerOrgObj) => {
const wrappedObject = Object.create(loggerOrgObj);
Object.assign(wrappedObject, {
error: wrapperFcn.bind(wrapperFcn, loggerOrgObj.error),
warn: wrapperFcn.bind(wrapperFcn, loggerOrgObj.warn),
info: wrapperFcn.bind(wrapperFcn, loggerOrgObj.info),
http: wrapperFcn.bind(wrapperFcn, loggerOrgObj.http),
verbose: wrapperFcn.bind(wrapperFcn, loggerOrgObj.verbose),
debug: wrapperFcn.bind(wrapperFcn, loggerOrgObj.debug),
silly: wrapperFcn.bind(wrapperFcn, loggerOrgObj.silly)
});
return wrappedObject;
};
return getWrappedLogger(logger);
};
module.exports = logger;
index.js
const logger = require('./logger.jsm')(true);
const circ = {x: 1};
circ.circ = circ;
// example of non-overridden method, which still works
logger.log({
level: 'info',
message: 'Logger launching.'
});
// examples of overridden methods, new behaviour
logger.error('This', 'is', 'log', 'level', 'error', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.warn('This', 'is', 'log', 'level', 'warn', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.info('This', 'is', 'log', 'level', 'info', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.http('This', 'is', 'log', 'level', 'http', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.verbose('This', 'is', 'log', 'level', 'verbose', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.debug('This', 'is', 'log', 'level', 'debug', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.silly('This', 'is', 'log', 'level', 'silly', 1, [2, 3], true, {foo: 'bar'}, circ);
// console.log comparison
console.log('This', 'is', 'pure', 'console', 'test', 1, [2, 3], true, {foo: 'bar'}, circ);
我的项目现在正在使用 winston logger 来记录到控制台。问题是,逗号在大多数地区被用作连接运算符,
喜欢logger.info("here is data", data )
数据始终是一个字符串,但记录的只是 "here is data" 而不是其他内容。
项目在大多数地方都使用逗号作为连接符,因此用“+”替换是乏味的。请赞成如何在逗号本身存在的情况下显示数据
你基本上有两种解决方法
1) 手动更改您的 logger.info 函数以获取多个参数,或者编写一个记录器包装器,在传递给 logger.info
之前连接字符串info = (...args) => {
const data = args.reduce((acc, item) => acc += item);
// or such kind of manual concatenation logic
logger.info(data);
}
2) 使用 es6 模板文字。所以不要使用 logger.info("here is data", data)
,而是使用
logger.info(`here is data ${data}`)
根据 Pressana 的回答,在我的 createLogger
函数中,它负责创建 winston 记录器并将其导出到需要记录的模块,我创建了一个记录器中间件。
这是一个例子
let env;
exports.createLogger = (envP) => {
env = envP;
const logger = winston.createLogger({
level: 'debug',
transports: [
new winston.transports.File({
filename: __dirname + '/error.log',
level: 'error'
}),
new winston.transports.File({
filename: __dirname + '/combined.log'
})
],
'colorize': true
});
const customLogger = getCustomLoggerMiddleware(logger);
if (env !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
return customLogger;
}
function getCustomLoggerMiddleware(logger) {
const customLogger = {};
customLogger.error = reduceLogger(logger.error)
customLogger.warn = reduceLogger(logger.warn)
customLogger.info = reduceLogger(logger.info)
customLogger.http = reduceLogger(logger.http)
customLogger.verbose = reduceLogger(logger.verbose)
customLogger.debug = reduceLogger(logger.debug)
customLogger.silly = reduceLogger(logger.silly)
return customLogger;
}
function reduceLogger(loggerFun) {
return (...args) => {
const data = args.reduce((acc, item) => acc += item);
loggerFun(data);
}
}
createLogger
函数是一个普通的 winston logger 构建器,魔法发生在 getCustomLoggerMiddleware
扩展 Mauricio 的回答是另一种观点。 区别在于它还记录了数组、对象(包括循环)。
logger.jsm
const path = require('path');
const winston = require('winston');
const safeStringify = require('fast-safe-stringify'); // comes with winston
const logger = (forceDev) => {
//
const DEVELOPMENT = forceDev || (process.env.NODE_ENV === 'development');
const logger = winston.createLogger({
level: (DEVELOPMENT) ? 'silly' : 'info',
levels: winston.config.npm.levels,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.align(),
winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
),
transports: DEVELOPMENT
? [
// Output logs to console
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
winston.format.align(),
winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
)
})
]
: [
// Write all logs to files
// With level `error` and below to `error.log`
new winston.transports.File({
filename: path.join(__dirname, '../logs/winston-error.log'),
level: 'error'
}),
// With level `info` and below to `combined.log`
new winston.transports.File({
filename: path.join(__dirname, '../logs/winston-combined.log')
})
]
});
process.on('unhandledRejection', (error) => {
logger.error(error.stack);
});
process.on('uncaughtException', (error) => {
logger.error(error.stack);
});
const wrapperFcn = (orgFcn, ...args) => {
orgFcn(
args
// .filter((arg) => arg !== 'whatever') // custom filter
.reduce((previous, current) => {
const replacer = null;
const space = null;
return `${previous} ${(typeof current === 'string' || current instanceof String) ? current : safeStringify(current, replacer, space)}`;
}, '')
);
};
const getWrappedLogger = (loggerOrgObj) => {
const wrappedObject = Object.create(loggerOrgObj);
Object.assign(wrappedObject, {
error: wrapperFcn.bind(wrapperFcn, loggerOrgObj.error),
warn: wrapperFcn.bind(wrapperFcn, loggerOrgObj.warn),
info: wrapperFcn.bind(wrapperFcn, loggerOrgObj.info),
http: wrapperFcn.bind(wrapperFcn, loggerOrgObj.http),
verbose: wrapperFcn.bind(wrapperFcn, loggerOrgObj.verbose),
debug: wrapperFcn.bind(wrapperFcn, loggerOrgObj.debug),
silly: wrapperFcn.bind(wrapperFcn, loggerOrgObj.silly)
});
return wrappedObject;
};
return getWrappedLogger(logger);
};
module.exports = logger;
index.js
const logger = require('./logger.jsm')(true);
const circ = {x: 1};
circ.circ = circ;
// example of non-overridden method, which still works
logger.log({
level: 'info',
message: 'Logger launching.'
});
// examples of overridden methods, new behaviour
logger.error('This', 'is', 'log', 'level', 'error', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.warn('This', 'is', 'log', 'level', 'warn', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.info('This', 'is', 'log', 'level', 'info', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.http('This', 'is', 'log', 'level', 'http', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.verbose('This', 'is', 'log', 'level', 'verbose', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.debug('This', 'is', 'log', 'level', 'debug', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.silly('This', 'is', 'log', 'level', 'silly', 1, [2, 3], true, {foo: 'bar'}, circ);
// console.log comparison
console.log('This', 'is', 'pure', 'console', 'test', 1, [2, 3], true, {foo: 'bar'}, circ);