'Winston log level filter
I am trying to use multiple transports. I also want to be able to log only one or more specific level(s) on a transport, where Winston logs from the given level and all which are more sever, so that I cannot by default be as selective as I would like to be.
I currently have 3 transports. One logs everything to console, one logs everything to file, and the third I want to log only levels HTTP_SEND and HTTP_RECV to a different file.
It is the third that I am having problems with. When I breakpoint the function levelFilter, I never see info.level != 'info'.
What am I doing wrongly? NB my code is based heavily on the answer to this question.
const winston = require('winston');
// Custom logging levels. We use all of those from https://datatracker.ietf.org/doc/html/rfc5424, although we change the values.
// We also add some custom levels of our own, which are commented with "".
const logLevels = {
none: 0, // no error logging - don't log with this, set it in process.env.LOG_LEVEL to turn off logging
// Could also be achieved by silent=true in winston.createLogger, from process.env, but this is simplest
emergency : 1, // system is unusable
alert: 2, // action must be taken immediately
critical: 3, // critical conditions
unhandledException: 4, // unhandled exception
error: 5, // error conditions
coding_bug: 6, // hard bug. E.g switch stemante hits default, etc
warning: 7, // warning conditions
notice: 8, // normal but significant condition
info: 9, // informational messages
debug: 10, // debug-level messages
HTTP_SEND: 11, // HTTP request sent
HTTP_RECV: 12, // HTTP request sent
called: 13, // function called
returns: 14, // function returns
log_everything: 15, // always the lowest level, so that we can log everything
};
const options = {
everythingToDailyLogFile: {
level: process.env.LOG_LEVEL || 'log_everything',
filename: `./logs/everything.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
},
httpActivityToLogFile: {
level: process.env.LOG_LEVEL || 'log_everything',
filename: `./logs/http_activity.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
},
everythingToConsole: {
level: process.env.LOG_LEVEL || 'log_everything',
handleExceptions: true,
json: false,
colorize: true,
},
};
const myFormat = winston.format.printf( ({ level, message, timestamp , ...metadata}) => {
let formattedMessage = `${timestamp} [${level}] : ${message} `
if(metadata) {
formattedMessage += JSON.stringify(metadata)
}
return formattedMessage
});
const levelFilter = (levelToFilterOn) =>
winston.format((info, _options) => {
// If no info object is returned from the formatter chain, nothing gets logged
if (toString.call(info.level) === "[object Array]")
{
if (info.level.includes(levelToFilterOn)) { return info; }
return false;
}
if (info.level != levelToFilterOn) { return false; }
return info;
})();
module.exports = winston.createLogger({
levels: logLevels,
transports: [
new winston.transports.Console({
format: winston.format.combine(
levelFilter(process.env.LOG_LEVEL || 'log_everything'),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
myFormat
)
}),
new winston.transports.File({
filename: "./logs/bet_squad.log",
format: winston.format.combine(
levelFilter(process.env.LOG_LEVEL || 'log_everything'),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
myFormat
)
}),
new winston.transports.File({
filename: "./logs/http_activity.log",
format: winston.format.combine(
levelFilter(process.env.LOG_LEVEL || ['HTTP_SEND', 'HTTP_RECV']),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
myFormat
)
}),
]
});
Solution 1:[1]
I tried your code and managed to make the third transport work. Your question is unclear, what do you mean by:
I never see info.level != 'info'.
In any case, if you want the third transport to work you have to configure a environment variable that matches the info level you define in your code
If you want your information level to be info, you must define an environment variable because of how you defined the parameter you pass to your levelFilter function.levelFilter(process.env.LOG_LEVEL || ['HTTP_SEND', 'HTTP_RECV']),
In order to use that process.env.LOG_LEVEL, you need to use the dotenv package that allows you to load env variable from a .env file.
Go Ahead and install that package:
npm install dotenv
Create a .env file at the root of your project and fill it with this code:
LOG_LEVEL=info
Add this line after your winston import as such:
const winston = require('winston');
const dotenv= require('dotenv').config();
Thanks to the dotenv package, the env variable you defined in the .env file is populated in the process.env object.
Now if you try logger.log('info', 'test message %s', 'my string'); you should be able to see the log appearing as well as the http_activity.log file populated.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jaro |
