'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 |