问题
The winston library is great for transports and flexibility. I'd like to use it to allow configuring levels and redirecting to files, but would like to reproduce console.log behavior for formatting, and having trouble.
Here's what I have so far:
const log = winston.createLogger({
level: 'debug',
format: format.combine(
format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
format.splat(),
format.colorize(),
format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
),
transports: [
new winston.transports.Stream({
stream: process.stderr,
level: 'debug',
})
],
});
log.info("Hello, %s", "Bob"); // Works: outputs "Hello, Bob"
But this don't work:
log.info("Hello", "Bob");
log.info("Hello", 123, {someObj: 1});
I'd like all extraneous objects after those taken up by splat()
to get added on, space-separated, and converted to string preferably using util.inspect()
.
回答1:
Answering my own question. The issue is with format.splat
-- pure util.format offers a simpler and more expected behavior. Replacing format.splat
with this utilFormatter
addresses the problem:
const util = require('util');
function transform(info, opts) {
const args = info[Symbol.for('splat')];
if (args) { info.message = util.format(info.message, ...args); }
return info;
}
function utilFormatter() { return {transform}; }
The example from my question then looks like so:
const log = winston.createLogger({
level: 'debug',
format: format.combine(
format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
utilFormatter(), // <-- this is what changed
format.colorize(),
format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
),
transports: [
new winston.transports.Stream({
stream: process.stderr,
level: 'debug',
})
],
});
log.info("Hello, %s", "Bob"); // Works: outputs "Hello, Bob"
log.info("Hello", "Bob"); // Works: outputs "Hello Bob"
log.info("Hello", 123, {someObj: 1}); // Works: outputs "Hello 123 { someObj: 1} "
回答2:
I had a similar problem, and after much trial and error i think i have a solution that you might be interested in. As i mentioned in my last update, we ended up building our own logger. well, over the weekend i published this logger to npm, and you're welcome to check it out.
It should have more or less identical output to console.log
. If you notice any inconsistencies, please let me know.
Also it also has multiple transports, and you can even pass custom ones, and you can even "wrap" the console functions to quickly integrate into your project.
example code:
const {createLogger,wrapConsole,unwrapConsole} = require('@r3wt/log');
const log = createLogger({log_level:'info',transports:['console','file']});
wrapConsole(log);//wraps the console globally with the log instance, making integration into large existing project less painful
// NOTE: only the following 4 functions are wrapped.
console.log('hi!');
console.warn('warning');
console.error('error');
console.info('info');
unwrapConsole();//unwrap console globally
You can find the library here as well as more code examples and basic documentation if you're interested, and PR's with features and fixes are welcomed and encouraged. code is MIT so you are free to fork and create your own version :-)
Best of luck, and i hope this helps.
回答3:
I did this workaround, but I'm finally not using winston :
const wrapper = (original: any) => {
return (...args: any[]): any => original(args.map((a) => `${a}`).join(' '))
}
logger.error = wrapper(logger.error)
logger.warn = wrapper(logger.warn)
logger.info = wrapper(logger.info)
By the way, logger
is an instance of winston.Logger
来源:https://stackoverflow.com/questions/55387738/how-to-make-winston-logging-library-work-like-console-log