Closed jasnell closed 8 years ago
I wonder if it might be simpler to just use an Error
or extend Error
instead of defining a new class. Obviously errors and warnings are different things, but I figured I'd throw the idea out there.
considered that but wanted to make sure there was a clear differentiation between the two. I think it's important for users not to conflate warnings with errors.
Is there a reason we wouldn't just print warnings to stderr
when stderr.isTTY
?
@Fishrock123 ... you mean as opposed to used console.error? Or something else?
No I mean why not just print by default when we're interacting with a console?
That's what this does. In the few places through the code that we currently print warnings, we just do an immediate console.error or console.trace. This PR moves that into an event handler and provides a more generic framework to report other kinds of warnings... By default, tho, the default handler simply just dumps that out to console.error.
unless I'm missing what you're saying :-).
@jasnell Right, ok, I see that now. So of course there will be concerns about this dumping warnings to log files, so what I was asking, or trying to suggest is something like https://github.com/rvagg/branch-diff/blob/v1.4.1/branch-diff.js#L77-L78 - i.e. only log when process.stderr.isTTY
. Reason being you're unlikely to be doing actual logging things on a direct console, I think.
Yeah I started looking at that after you asked. It's definitely a possibility. On Jan 20, 2016 4:09 PM, "Jeremiah Senkpiel" notifications@github.com wrote:
@jasnell https://github.com/jasnell Right, ok, I see that now. So of course there will be concerns about this dumping warnings to log files, so what I was asking, or trying to suggest is something like https://github.com/rvagg/branch-diff/blob/v1.4.1/branch-diff.js#L77-L78 - i.e. only log when process.stderr.isTTY. Reason being you're unlikely to be doing actual logging things on a direct console, I think.
β Reply to this email directly or view it on GitHub https://github.com/nodejs/node/pull/4782#issuecomment-173408507.
Very nice idea!
Left some comments. I don't know if it's really an improvement, I guess I'm -0.
I'm not really so sure what the value of exposing this as an API is?
I'd like to be able to have more warnings as I outlined above, but what would a module actually do with this other than print / log them?
This tries to keep the new API surface to a minimum, just a new event and an error like object. The main thing this tries to accomplish is give a bit more flexibility in how those warnings are printed/logged. For instance, an application that uses a custom logging solution can register a handler to do custom logging of warnings so that they appear properly alongside other logged events:
const winston = require('winston');
// .. configure winston
process.on('warn', (warning) => {
winston.warn(warning.message, warning);
});
Another example would be an application built on Electron that surfaces the warnings in the GUI somehow as opposed to the console (where they quite possibly wouldn't be seen).
I think it might be a good idea to make warnings a thing, document the hook and allow libraries to emit their own warnings in a standard way.
In second thought it's the sort of thing that needs to be discussed more in depth in an issue first.
There's no particular rush on landing this so keeping it open for discussion for a while is just fine :-)
other example would be an application built on Electron that surfaces the warnings in the GUI somehow as opposed to the console (where they quite possibly wouldn't be seen).
Ah, that is an excellent note. cc @zcbenz What sort of API would be useful to you folks for warnings?
Ah, that is an excellent note. cc @zcbenz What sort of API would be useful to you folks for warnings?
The warn
event looks perfect to me.
Great feature! I agree with @cjihrig though that an Error
object would be more intuitive (despite the name). At least with an Error object I know which properties to expect (even without docs).
One question though, could it be made so that if there is a listener for "warn"
, it automatically doesn't print to stderr? Quite like how "error"
and signal listening works. Listening turns off the default behavior.
Yes, we can do that, however it may be a bit surprising. Users may not be aware that a module has registered a listener and they could end up missing warnings they need to see.
On Thu, Jan 21, 2016 at 6:54 PM, Ron Korving notifications@github.com wrote:
Great feature! I agree with @cjihrig https://github.com/cjihrig though that an Error object would be more intuitive (despite the name). At least with an Error object I know which properties to expect (even without docs).
One question though, could it be made so that if there is a listener for "warn", it automatically doesn't print to stderr? Quite like how error and signal listening works. Listening turns off the default behavior.
β Reply to this email directly or view it on GitHub https://github.com/nodejs/node/pull/4782#issuecomment-173787784.
I guess some feedback from other users and collaborators on the matter would be good then.
@trevnorris @Fishrock123 @ronkorving ... pushed an update that addresses many of the comments ( I hope :-) ...)
@shigeki ... I'd like to get your input on this as well. I'd like to be able to use this mechanism to have node raise security warnings when users do things that are known to be unsafe... for instance: https://nodejs.org/dist/latest-v5.x/docs/api/crypto.html#crypto_support_for_weak_or_compromised_algorithms
There is a lot of potential in standardizing it - libraries would be able to dispatch events for problematic usage in an easy to deal with way.
@nodejs/ctc ... updated. ping.
I think it would be really nice to know how clients will interact with this API. Are userland libraries expected to emit their own warn
events?
@bnoordhuis @benjamingr .. updated!
@bnoordhuis @benjamingr @nodejs/ctc: I believe this is ready to go. I've updated based on the feedback, rebased and updated.
@bnoordhuis / @Fishrock123 ... I removed the TTY restriction. After going through a bunch of scenarios, there are too many cases where not getting the warning (particularly deprecation warnings) would be problematic.
I'd like to get this landed soon.
Just in the nick of time perhaps, and at the risk of bike shedding, but what do you think is the more common used event name for warnings? on("warn")
or on("warning")
? I'm personally really fine with either, but I can imagine some precedent has already been set somewhere, so I just wanna make sure the right naming choice is made. Once this goes in, there's no going back on the name.
@ronkorving ... I'm not quite sure there is enough of a precedent to say really. I picked warn
because it's three fewer characters to type than warning
;-)
I'm not one of those people typing err
instead of error
, but that may just be me too :)
I was just thinking:
process.on('error', function (error) { /* ... */ });
process.on('warning', function (warning) { /* ... */ });
The thing you receive is the thing you listen for. While "warn" is a verb, "error" is not.
Ok, makes sense to me. I'll switch it to 'warning'
;-)
@ronkorving ... done!
Cool :+1:
Note that bluebird starts using this hook today, still undocumented. We use it in order to warn against common misuses of promises.
@benjamingr: is bluebird using 'warn' or 'warning' as the event name? Want to make sure we're in sync.
@benjamingr a reminder that emitting events on objects you don't own is a bad idea (unless it's a documented use case)
In most cases, yes. For this particular mechanism it ought to be safe given that the semantics are clear. Is there something I'm missing tho? On Feb 12, 2016 5:39 AM, "Vladimir Kurchatkin" notifications@github.com wrote:
@benjamingr https://github.com/benjamingr a reminder that emitting events on objects you don't own is a bad idea
β Reply to this email directly or view it on GitHub https://github.com/nodejs/node/pull/4782#issuecomment-183333025.
@jasnell we need to document these cases, although I'd prefer special hook designed for each case (e.g. process.emitWarning
instead of process.emit('warning'
)
That's a possibility for sure. It gives us more flexibility later to evolve the mechanism also. On Feb 12, 2016 6:05 AM, "Vladimir Kurchatkin" notifications@github.com wrote:
@jasnell https://github.com/jasnell we need to document these cases, although I'd prefer special hook designed for each case (e.g. process.emitWarning instead of process.emit('warning')
β Reply to this email directly or view it on GitHub https://github.com/nodejs/node/pull/4782#issuecomment-183344160.
Then process.warn(warning)
may be good naming. In the future, behavior may not just be limited to event emission. I like the idea :+1:
We added it to bluebird to provoke this discussion exactly. I appreciate your concerns. I'd love for this to be ctc agenda so it can be discussed whether or not this should be user facing.
I've already heard from several people who definitely would like this to be user facing, and yes, for the over whelming majority of cases, emitting events on objects you don't own is bad practice because you simply cannot know what the side effects are. The original intent was for this to cover internal warnings but given the expressed interest, a process.emitWarning method does make a lot of sense (and would be trivial to add).
Thinking about it, a process.warn method might be easily confused (and abused) as a generic log warn mechanism (e.g. console.warn), which is not really the intent. emitWarning is sufficiently different to avoid such confusion. On Feb 12, 2016 6:32 AM, "Benjamin Gruenbaum" notifications@github.com wrote:
We added it to bluebird to provoke this discussion exactly. I appreciate your concerns. I'd love for this to be ctc agenda so it can be discussed whether or not this should be user facing.
β Reply to this email directly or view it on GitHub https://github.com/nodejs/node/pull/4782#issuecomment-183352913.
@vkurchatkin @benjamingr @ronkorving ... ok, I've added process.emitWarning()
... there are essentially three flavors:
// String
process.emitWarning('this is the warning message');
// Object
process.emitWarning({name: 'FooWarning', message: 'this is the warning message');
// Error object
var warning = getErrorObjectSomehow();
process.emitWarning(warning);
The first two will be coerced into Error objects before passing off to the process.on('warning')
event.
An optional warned
parameter can be passed to avoid duplicate warnings...
var warned = false;
function doWarning() {
warned = process.emitWarning('only warn once', warned);
}
doWarning(); // emits the warning
doWarning(); // emits nothing
Documentation is updated and a test case provided.
@node/ctc ... can I get another round of review on this one? ;-)
We'd still likely use a process.emit("warning"
manually because it'd work in older versions of node and Bluebird supports 0.10 (wait, do we?)
Well, you certainly wouldn't get the default handling of the process warning in older versions of node so you'd need to watch out for that... your warnings may go completely unnoticed. The process.emitWarning
method would be simple to polyfill also, which would likely be more maintainable long term.
emitting events on objects you don't own is bad practice because you simply cannot know what the side effects are.
Well, typically objects you don't own wouldn't give you the ability in the first place, process being an EventEmitter
means it explicitly exports the capability to emit events on it. This has proven useful for unhandledRejection
and works beautifully in userland. A channel to say "hey, what you're doing is wrong!" without relying on the temrinal output is something userland could use - since it lets application developers dictate a clear policy for warnings and separates debug from release by having different handlers.
Process plays the part of "the object everyone has the capability to listen to" and sometimes you need to fire a global event (unhandledRejection being a good example).
The only problematic part in this story is "why has this not emerged from userland". To be fair users asked for regardless of this pr (e.g. https://github.com/petkaantonov/bluebird/issues/980).
Adding this to the ctc-agenda because I'd like to get review and sign off...
The warned
parameter is kind of odd. If the logic for whether this should be emitted or not is at the source of the call then surely it could just as easily be surrounded in an if
at that same place. The code is already doing this (if (warned) return true;
) so it seems like an odd way to hand off responsibility for whether or not to take action. Unless there's some larger plan in mind for this argument?
@rvagg ... feedback addressed. I removed the warned
argument from emitWarning and added the Error.call(this)
In several places throughout the code we write directly to stderr to report warnings (deprecation, possible eventemitter memory leak). The current design of simply dumping the text to stderr is less than ideal. This PR introduces a new "Process Warnings" mechanism that emits 'warn' events on the global process object. These are invoked with a
Warning
object that is similar in structure to anError
in that they have a name, message and stack trace.By default, these warnings will be printed to stderr. This can be suppressed using the
--no-warnings
command line flag, however the 'warn' event will still be emitted by the process, allowing applications to handle the warnings in custom ways.The
--trace-warnings
command line flag will tell Node.js to print the full stack trace of warnings as part of the default handling.The existing
--no-deprecation
,--throw-deprecation
and--trace-deprecation
flags continue to work as they currently do, but the exact output of the warning message is modified to occur on process.nextTick(). The stack trace for the warning, however, is preserved and shows the correct call site.Test cases and documentation are included.
Refs: https://github.com/nodejs/node-eps/pull/4#issuecomment-173079195