-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3.0.0] Error object is not parsed or printed #1338
Comments
We have some test coverage for this, but clearly we need more. What's going on under the covers:
console.log(JSON.stringify(new Error('lol nothing here')));
// '{}' From a design perspective |
If anyone is looking for a quick work-around you can include const winston = require('../');
const { createLogger, format, transports } = winston;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new transports.Console()
]
});
// Error as message
console.log('Run FIRST test...');
logger.log({ level: 'error', message: new Error('FIRST test error') });
// Error as info (one argument)
console.log('\nRun SECOND test...');
const err = new Error('SECOND test error');
err.level = 'info';
logger.info(err);
// Error as info (two arguments);
console.log('\nRun THIRD test...');
logger.log('info', new Error('THIRD test error')); |
@indexzero, I tried to follow your workaround, but it's not working. Do you know why? Formatter: const level = settings.debug ? 'debug' : 'info';
const printFormat = winston.format.printf(info => `${info.timestamp} - ${info.level}: ${info.message}`);
const enumerateErrorFormat = winston.format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack,
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack,
}, info);
}
return info;
});
const consoleLogger = winston.createLogger({
level,
format: winston.format.timestamp(),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
enumerateErrorFormat(),
printFormat,
),
}),
],
}); Code: try {
// Some code throwing error
} catch (err) {
logger.error(err);
} Output:
Info object: { level: '\u001b[31merror\u001b[39m', timestamp: '2018-06-28T21:17:25.140Z', [Symbol(level)]: 'error' } Where is the message attribute in the error log? |
@sandrocsimas I noticed that you need to give the enumerateErrorFormat function to the default formatter of the logger in order to make it work. Formatter const consoleLogger = winston.createLogger({
level,
format: winston.format.combine(
winston.format.timestamp(),
enumerateErrorFormat()
),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
printFormat,
),
}),
],
}); I still don't understand why tho |
I think I'm experiencing the same bug as @sandrocsimas. Here is my logger config: logger.js const winston = require('winston');
const {configure, format} = winston;
const {combine, colorize, timestamp, printf} = format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const myConsoleFormat = printf(info => {
console.log('** Info Object: **');
console.log(info);
console.log('** Winston Output: **');
return `${info.level}: ${info.message}`;
});
winston.configure({
transports: [
new winston.transports.Console({
format: combine(
colorize(),
enumerateErrorFormat(),
myConsoleFormat
),
})
]
}); If I test it with this block of code: Test A const logger = require('winston');
try {
throw(new Error());
} catch (err) {
logger.error(err);
} where Output A
Where However, if I test it with this block of code: Test B const logger = require('winston');
try {
throw(new Error('This causes error: undefined'));
} catch (err) {
logger.error(err);
} Where Output B
As you can see I get the same Note, if I try this block of code: Test C const logger = require('winston');
try {
throw(new Error('This should work'));
} catch (err) {
logger.log({level: 'error', message: err});
} Where I use |
I have the same problem. I'm new in winston. I tried @indexzero solution but not working. Do you have any solution? |
@nvtuan305, did you try @indexzero's solution exactly or did you edit it a bit? If so could you provide sample code? His code should work if you're using |
Am I missing something, or is it a complete headache (or even impossible?) to get the same output one easily gets from console.log/error/warn? try {
// ...
throw new Error('foo');
} catch (e) {
console.error('Caught error:', e); // convenient, informative
logger.error('Caught error:', e); // nope, the second parameter is something else (couldn't find docs)
logger.error(`Caught error: ${e}`); // stack lost
logger.error(`Caught error: ${JSON.stringify(e)}`); // Caught error: {}
} What is the equivalent winston code to get the same output as And where is the documentation for the parameters taken by the convenience methods on the logger object? |
logger.error('Caught error:', e); This doesn't work because, unlike Note that you can also use logger.error(`Caught error: ${e}`); I can not definitively say why this does not output the stack, but I do know this is not a problem with winston. If you try logger.error(`Caught error: ${JSON.stringify(e)}`) This one gets to the heart of what this bug thread is about. First you must understand some technical details about javascript. Note that if you try
Basically, because Luckily, because of the way winston 3.0 was designed (props to the winston team) we have a workaround for this that @indexzero gave. I'll help explain it. First you create this function: const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
}); From the docs Streams, objectMode, and info objects the info object has two properties, Next you'll create this logger which uses the const logger = createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new transports.Console()
]
}); This will take whatever Still, it would be nice if we didn't have to create that Some final notes. This only works if you use
There is another bug in winston where this code does not work, as I explained in my other post above:
For some reason the |
@SamuelMaddox17 @indexzero Thank you! I tried using |
Can this please get fixed for logger.error, etc? It is cumbersome and verbose to use |
Hey all, I'm looking into this. @indexzero : still think the best idea is to essentially add the const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
logger.error(new Error('whatever')); |
Upon further investigation it seems that the const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
winston.configure({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
})
]
});
winston.error(new Error('whatever')); Second, I agree that Finally, I'd like to note the code example given by @DABH causes the stack to not "print pretty" if you will; at least on my machine running macOS High Sierra. This is what it looks like for me:
As you can see, when outputting the error with a to JSON function the newline characters Thank you for looking more into this @DABH |
FYI this is where I've gotten to after playing with this a bit: import winston from 'winston';
const format = winston.format;
const printNice = format.printf(info => {
const {level, message} = info;
return `Logging Level: ${level} - Logging Message: ${message}`;
});
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: `${info.message.message}\n============\n${info.message.stack}`
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: `${info.message}\n============\n${info.stack}`
}, info);
}
return info;
});
const logger = winston.createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console({
format: format.combine(
format.colorize(),
printNice,
),
})
]
});
export default logger; |
The issue is caused by this bug : winstonjs/winston-transport#31 |
We definitely used this form in winston2.x with no problems. |
@SamuelMaddox17
it works thx |
Okay, I discovered something. My comment from September 3rd is wrong. This isn't a problem with the default logger. This is a problem with where you define const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
logger.error(new Error('whatever')); If you remove this: const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
}); And replace it with this: const logger = winston.createLogger({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
}),
],
}); Then the Here is your code sample with my code change so you can easily run and test: const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
}),
],
});
logger.error(new Error('whatever')); Hopefully this helps get to the root of the problem. |
I created #1527 This covers all options. However some tests fail so I have closed it for now. The failures are expected given the fix, but I don't believe I am in a position to make the call to amend/delete the tests. Failing build is here https://travis-ci.org/winstonjs/winston/jobs/453012141 and its obvious why the tests now fail when you read the test code: Line 668 in c42ab7f
Thoughts? |
I think the problem is in this line |
@tiagonapoli your solution about using
It is fairly painful configuring this logger... Could it not just behave like |
@will093 same here. Been on that issue again and don't get it why my |
…s). Fixes winstonjs#1338, winstonjs#1486 (winstonjs#1562) * [tiny dist] Whitespace. package-lock.json * [test] Add E2E integration tests with logform `errors` format. * [test] 5:00pm. Press return. * [fix test] More E2E errors coverage. * [test] Test custom error properties. * [tiny doc] Make note of duplicate coverage in `logger`. Update minor formatting. * [test] All E2E tests work except for one... * [fix test doc] All 14 variations of handling `new Error()` now work as most folks expect. * [tiny] Fix up file header. * [dist] Bump to `[email protected]` * [fix tiny] Whitespace. * s/req_id/requestId/ * [fix test] Address PR comments. Add test coverage for defaultMeta over .child(additionalMeta)
My 2¢ // Enable console logging when not in production
if (process.env.NODE_ENV !== "production") {
logger.add(new transports.Console({
format: format.combine(
format.colorize(),
format.simple(),
format.printf(info => {
const { level, ...rest } = info;
let rtn = "";
// rtn += info.timestamp;
rtn += "[" + info.level + "] ";
if (rest.stack) {
rtn += rest.message.replace(rest.stack.split("\n")[0].substr(7),"");
rtn += "\n";
rtn += "[" + level + "] ";
rtn += rest.stack.replace(/\n/g, `\n[${level}]\t`);
} else {
rtn += rest.message;
}
return rtn;
}),
),
}));
} Example for |
using @tiagonapoli and @will093's solution of adding it to just the parent seems to be the easiest way to support directly logging errors and still logging messages -- here's a full example of a minimal setup w/ timestamps: const createLogger = () => {
const logFormatter = winston.format.printf(info => {
let { timestamp, level, code, stack, message } = info;
// print out http error code w/ a space if we have one
code = code ? ` ${code}` : '';
// print the stack if we have it, message otherwise.
message = stack || message;
return `${timestamp} ${level}${code}: ${message}`;
});
return winston.createLogger({
level: 'info',
// put the errors formatter in the parent for some reason, only needed there:
format: winston.format.errors({ stack: true }),
transports: new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
logFormatter
),
});
}; works with a stack when called with an error like:
this does not attempt to solve winston's Also, if you like json logs you can drop the |
where is trace() definition? |
any answer on this? |
quick and dirty, but lacking proper formatting on errors. Still better than nothing.. const winston = require('winston');
const logger = winston.createLogger({
level: 'debug',
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
new winston.transports.Console({ format: winston.format.json() })
],
});
logger.format = winston.format.combine(
winston.format.errors({ stack: true }),
) |
I switched to pino and never looked back instead of wasting so much time trying to make something work that should have been working out of the box since it's the most common use case. |
format.errors({ stack: true }) doesn't seem to work when using a different formatter per transport (winstonjs/winston#1338 (comment))
To leave my bits I have put together the following winston configuration to accommodate both errors and multiple parameters in the logs. const winston = require('winston');
const util = require('util');
const enumerateErrorFormat = winston.format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
level: 'silly',
format: winston.format.combine(
enumerateErrorFormat(),
{
transform: (info) => {
const args = [info.message, ...(info[Symbol.for('splat')] || [])];
info.message = args;
const msg = args.map(arg => {
if (typeof arg == 'object')
return util.inspect(arg, {compact: true, depth: Infinity});
return arg;
}).join(' ');
info[Symbol.for('message')] = `${info[Symbol.for('level')]}: ${msg}${info.stack ? ' ' + info.stack : ''}`;
return info;
}
}
)
});
logger.add(new winston.transports.Console())
logger.add(new winston.transports.File({filename: './logs.txt.'}));
logger.silly('hello silly', 1234, 'my condolence', {ahmet:1, meh:[{ahmet:1, meh:'alo'},{ahmet:1, meh:'alo'}]}, [{ahmet:1, meh:'alo'},{ahmet:1, meh:'alo'}]);
logger.debug('hello debug', () => console.log(1+2));
logger.info('hello info');
logger.warn('hello warn');
logger.error('hello error');
logger.error(new Error('error 1'), 123, new Error('error 2')); |
You can define a simple ConsoleLogger to show complete Error - objects. IMHO the amount of code to get the result is okay for the purpose. const { createLogger } = require('winston');
const Transport = require('winston-transport');
/**
* The simple "custom" console - logger,
* which logs the complete Error - object.
*/
class ConsoleLogger extends Transport {
constructor(opts) {
super(opts);
}
log(info, callback) {
console.log(info);
callback();
}
};
const logger = createLogger({
transports: [
// use the ConsoleLogger instead of the winston "cOnSoLEtRaNSpOrt"
new ConsoleLogger()
]
});
let err = new Error('this is a test');
logger.log({ level: 'error', message: err });
|
It appears that the original issue this thread was supposed to be about was solved a while ago and it continues on in closed state because a second issue brought up still requires a workaround. This comment from a project founder may shed some light on why that is likely to remain the case for a while. |
This will enhance the logging of error messages in catch blocks (the javascript Error object). Due to a problem on wiston, when logging an error object, the winston just prints the messages, and all important details (like error line, etc,) is hidden. Details: winstonjs/winston#1338 For example, if I'm developing a module or something fails with an Error, this is what is printed in the wiki.js log: 2022-09-16T02:31:41.383Z [MASTER] info: ======================================= 2022-09-16T02:31:41.385Z [MASTER] info: = Wiki.js 2.5.286 ===================== 2022-09-16T02:31:41.385Z [MASTER] info: ======================================= 2022-09-16T02:31:41.386Z [MASTER] info: Initializing... 2022-09-16T02:31:42.334Z [MASTER] info: Using database driver pg for postgres [ OK ] 2022-09-16T02:31:42.337Z [MASTER] info: Connecting to database... 2022-09-16T02:31:42.501Z [MASTER] info: Database Connection Successful [ OK ] 2022-09-16T02:31:43.507Z [MASTER] warn: Mail is not setup! Please set the configuration in the administration area! 2022-09-16T02:31:43.675Z [MASTER] info: Loading GraphQL Schema... 2022-09-16T02:31:45.155Z [MASTER] info: GraphQL Schema: [ OK ] 2022-09-16T02:31:45.437Z [MASTER] error: SOME_ERROR is not defined After this fix, the error is printed with more info: Loading configuration from T:\powerdocs\wikijs\config.yml... OK 2022-09-16T02:32:08.650Z [MASTER] info: ======================================= 2022-09-16T02:32:08.652Z [MASTER] info: = Wiki.js 2.5.286 ===================== 2022-09-16T02:32:08.653Z [MASTER] info: ======================================= 2022-09-16T02:32:08.653Z [MASTER] info: Initializing... 2022-09-16T02:32:09.627Z [MASTER] info: Using database driver pg for postgres [ OK ] 2022-09-16T02:32:09.632Z [MASTER] info: Connecting to database... 2022-09-16T02:32:09.897Z [MASTER] info: Database Connection Successful [ OK ] 2022-09-16T02:32:10.932Z [MASTER] warn: Mail is not setup! Please set the configuration in the administration area! 2022-09-16T02:32:11.116Z [MASTER] info: Loading GraphQL Schema... 2022-09-16T02:32:12.949Z [MASTER] info: GraphQL Schema: [ OK ] 2022-09-16T02:32:13.276Z [MASTER] error: ReferenceError: SOME_ERROR is not defined at module.exports (T:\wikijs\server\master.js:172:3) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async Object.bootMaster (T:\wikijs\server\core\kernel.js:60:9)
Doesn't work |
I searched for node logger in youtube and can only find this package. All I want is just log to file (may be a little prettify), otherwise I have to implement myself. |
See my comment here : winstonjs/logform#100 This is an internal bug inside base Transport class, that needs to be adressed. |
Long running issue given the above answers.
|
Please tell us about your environment:
winston
version?[email protected]
node -v
outputs: v8.11.1What is the problem?
Logging a node
Error
object results in an empty message:Example:
Resulting output:
Also:
Results in:
What do you expect to happen instead?
I Expect the message key to have at least the error message included in it. If I try a custom formatter,
info
also doesn't have the error object in it so it must be stripped out somewhere?Other information
Let me know how I can help - happy to flick a PR but I don't know my way around
[email protected]
enough yet to find itThe text was updated successfully, but these errors were encountered: