I am working on node Js logging library. I am using winston for this.I created log files but I stuck when I want to create two log files.Suppose I have to create all log file which contain all logs and error log file which contain only error logs.But I stuck here:
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
const tsFormat = () => (new Date()).toLocaleTimeString();
let logger = new(winston.Logger)({
transports: [
new(winston.transports.Console)({
level: 'debug',
timestamp: tsFormat,
handleExceptions: true,
colorize: true,
json: false
}),
new(winston.transports.File)({
name: 'all-file',
handleExceptions: true,
filename: `${logDir}/all-file.log`,
level: 'debug',
maxsize: 100000000,
json: true
}),
new(winston.transports.File)({
name: 'error-file',
handleExceptions: true,
filename: `${logDir}/error-file.log`,
level: 'error',
maxsize: 100000000,
json: false
})
]
});
I want that error log show different type of console than debug console.But by default its only taking debug one. how can I manually add console config for both files.When I try to add another transport.console it shows error.
Transport already attached: console, assign a different name
var winston = require('winston');
let consoleLogger = function(options){
return new (winston.Logger)({
transports: [
new (winston.transports.Console)(options),
]
});
}
// the CustomTransport is to prevent error log show multiple times
class CustomTransport extends winston.Transport {
constructor(options) {
super(options);
this.options = options;
this.levels = options && options.levels || [this.level];
}
log(level, msg, meta, callback) {
if(this.levels.indexOf(level) > -1){
consoleLogger(this.options)[level](msg, meta);
}
callback(null, true);
}
}
winston.transports.CustomTransport = CustomTransport;
const tsFormat = () => (new Date()).toLocaleTimeString();
var logger = new (winston.Logger)({
transports: [
// add name attribute to prevent Transport already attached error
// no error log for this transport
new (winston.transports.CustomTransport)(
{
name: 'info-console',
level: 'debug',
levels : ['debug', 'verbose', 'info', 'warn'],
timestamp: tsFormat,
handleExceptions: true,
colorize: true,
json: false
}
),
// only error log for this transport, modify the configuration as you need
new (winston.transports.CustomTransport)(
{
name: 'error-console',
level: 'error',
timestamp: tsFormat,
handleExceptions: true,
colorize: true,
json: false
}
),
new (winston.transports.File)(
{
name: 'info-file',
filename: 'info.log',
timestamp: true,
maxsize: 1024000,
level: 'info'
}),
new (winston.transports.File)(
{
name: 'error-file',
filename: 'error.txt',
timestamp: true,
maxsize: 1024000,
level: 'error'
})
]});
usage:
logger.debug('debug');
logger.error('error');
Related
I created a simple Winston logger for my node application, but the configuration with timestamps not working, what it means? It means that all of the logs isn't with the timestamp.
Example:
const { createLogger, format, transports } = require('winston');
const logger = createLogger({
transports: [
new transports.File({
maxsize: 5120000,
maxFiles: 20,
filename: `logs/logs.log`,
colorize: true,
json: true,
timestamp: true
}),
new transports.Console({
level: "debug",
timestamp: true,
format: format.combine(
format.colorize(),
format.simple(),
format.timestamp()
)
})
]
});
module.exports = { logger };
simple() format does not output timestamp. so you should define a custom format using printf:
const { createLogger, format, transports } = require('winston');
const myFormat = format.printf(({ level, message, label, timestamp }) => {
return `${timestamp} [${label}] ${level}: ${message}`;
});
const logger = createLogger({
transports: [
new transports.File({
maxsize: 5120000,
maxFiles: 20,
filename: `logs/logs.log`,
timestamp: true,
json: true,
}),
new transports.Console({
level: "debug",
timestamp: true,
format: format.combine(
format.timestamp(),
format.colorize(),
myFormat,
)
})
]
});
module.exports = { logger };
i also moved timestamp() format before the myFormat as it should fill timestamp of message before it reaches the printf.
I tried with Winston for logger. I used in one project their It's working well when I copy paste the code from their to the current existing project than I face an issue like TypeError: winston.Logger is not a constructor
let logger = new (winston.Logger)({
^
TypeError: winston.Logger is not a constructor
Please guide me, Why this error and what should I have to do for solving this issue.
"morgan": "^1.9.0", "winston": "^3.0.0"
Following is my code in logger.js file.
var appRoot = require('app-root-path');
var winston = require('winston');
var options = {
file: {
level: 'info',
name: 'file.info',
filename: `${appRoot}/logs/app.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 100,
colorize: true,
},
errorFile: {
level: 'error',
name: 'file.error',
filename: `${appRoot}/logs/error.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 100,
colorize: true,
},
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true,
},
};
// your centralized logger object
let logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)(options.console),
new (winston.transports.File)(options.errorFile),
new (winston.transports.File)(options.file)
],
exitOnError: false, // do not exit on handled exceptions
});
As you mention, you are using 3.0.0, you can not not use winston.Logger, you may refer library code( https://github.com/winstonjs/winston/blob/master/lib/winston.js#L178 )
You need to make small update in your code, use winston.createLogger instead of new (winston.Logger)
// your centralized logger object
let logger = winston.createLogger({
transports: [
new (winston.transports.Console)(options.console),
new (winston.transports.File)(options.errorFile),
new (winston.transports.File)(options.file)
],
exitOnError: false, // do not exit on handled exceptions
});
logger.js
var winston = require('winston');
var logger = new winston.createLogger({
transports: [
new winston.transports.Console({
level: 'info',
handleExceptions: true,
json: false,
colorize: true,
timestamp: true
}),
new winston.transports.Console({
level: 'error',
handleExceptions: true,
json: false,
colorize: true,
timestamp: true
}),
],
exitOnError: false
});
module.exports = logger;
module.exports.stream = {
write: function(message, encoding){
logger.info(message);
}
};
Whenever I call logger.info or logger.error, it'll log a json object to the screen without colors. What is wrong with my logger that is causing this issue? The timestamp isn't printing on this as well.
Looks like you are mixing the old syntax with the v3 syntax. According to the documentation you can write it something like this:
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, printf, colorize } = format;
const myFormat = printf(info => {
return `${info.timestamp} ${info.level}: ${info.message}`;
});
const logger = createLogger({
format: combine(
colorize(),
timestamp(),
myFormat
),
transports: [
new transports.Console({
level: 'info',
handleExceptions: true
}),
new transports.Console({
level: 'error',
handleExceptions: true
}),
],
exitOnError: false
});
module.exports = logger;
module.exports.stream = {
write: function(message, encoding){
logger.info(message);
}
};
This will show timestamps and colors.
There is also an upgrade guide here that shows the differences between v2 and v3.
I have two different winston loggers which look like this (there are two separate ones as they write different logs depending on my functions) - :
var security = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
})
]
});
And then I have one more for :
var system = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
})
]
});
However, I also have a verbose.log file, where I want all of the logs from the security and system log file to be written to the verbose too. Whats the best way of doing that?
I tried adding the filename (i.e. verbose.log) to each of the transports, but this does not work as I get the error
Error: Transport already attached: dailyRotateFile, assign a different name
It is a common problem with winston, but a simple one to solve.
Due to how winston is coded, it cannot differenciate your two transport himself, and need you to explicitly declare them as separate by giving them different names:
var security = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
//=>
name: 'foo',
//<=
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
})
]
});
var system = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
//=>
name: 'bar',
//<=
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
})
]
});
The name itself doesn't matter as long as it is different, a easy way to do that is to use the filename along with some other identifier for the transport.
Source: issue #101 of the official Github
EDIT:
var verbose = new(require('winston-daily-rotate-file'))({
name: 'baz',
filename: logDir + '/-verbose.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
})
var security = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
//=>
name: 'foo',
//<=
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
}),
//=>
verbose
//<=
]
});
var system = new(winston.Logger)({
transports: [
new(require('winston-daily-rotate-file'))({
//=>
name: 'bar',
//<=
filename: logDir + '/-security.log',
datePattern: 'dd-MM-yyyy',
prepend: true,
json: false,
timestamp: function() {
return moment().format('D/MM/YYYY HH:mm:ss:SSS');
}
}),
//=>
verbose
//<=
]
});
You can filter out logs by creating two or more loggers as per your requirement and adding name property to them. Adding a common transport function in both logger worked for me.
const winston = require('winston');
const combinedLogger = new winston.transports.File({
name: "data",
filename: "./logs/combined.log",
level: "info",
})
const infoLogger = winston.createLogger({
defaultMeta: { service: "log-service" },
transports: [
new winston.transports.File({
name: "info",
filename: "./logs/info.log",
level: "info",
}),
combinedLogger
],
});
const errorLogger = winston.createLogger({
defaultMeta: { service: "log-service" },
transports: [
new winston.transports.File({
name: "error",
filename: "./logs/error.log",
level: "error",
}),
combinedLogger
],
});
const logger = {
info: (params) => {
return infoLogger.info(params);
},
error: (params) => {
return errorLogger.error(params);
},
};
logger.info("info log"); // Will goto info.log & combined.log
logger.error("error log"); // Will goto error.log & combined.log
I have my logging configured like this in my express/nodejs web application. The timestamp in the log messages are in GMT. Is there a way to get the local time instead?
var winston = require('winston');
winston.emitErrs = true;
var logger = new winston.Logger({
transports: [
new winston.transports.File({
level: 'debug',
filename: './logs/all-logs.log',
handleExceptions: true,
json: false,
maxsize: 5242880, //5MB
maxFiles: 5,
colorize: false,
timestamp:true
}),
new winston.transports.Console({
timestamp :true,
level: 'debug',
handleExceptions: true,
json: false,
colorize: true
})
],
exitOnError: false
});
module.exports = logger;
module.exports.stream = {
write: function(message, encoding){
logger.info(message);
}
};
This is a sample log out put I get
2014-11-18T18:30:33.570Z - debug: Authenticated
Have you tried with :
function myTimestamp() {
return new Date().toString();
};
var logger = new winston.Logger({
transports: [
new winston.transports.File({
level: 'debug',
filename: './logs/all-logs.log',
handleExceptions: true,
json: false,
maxsize: 5242880, //5MB
maxFiles: 5,
colorize: false,
timestamp: myTimestamp
}),
new winston.transports.Console({
timestamp :true,
level: 'debug',
handleExceptions: true,
json: false,
colorize: true
})
],
exitOnError: false
});