nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
106.65k stars 29.08k forks source link

process: add 'warning' event #4782

Closed jasnell closed 8 years ago

jasnell commented 8 years ago

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 an Error 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

Fishrock123 commented 8 years ago

cc @nodejs/ctc I am not so sure I a comfortable with how deprecations work here, but a couple more opinions would help. (Since we are more or less committing to this api long-term.)

Maybe we should take a couple points to this week's ctc meeting if that would be easier?

Fishrock123 commented 8 years ago

My feeling is that:

jasnell commented 8 years ago

@Fishrock123 .. fair enough. To be honest, I'd be quite happy deprecating the *-deprecation flags in favor of the new more generalized *-warning flags... including having a --throw-warning= flag whose value would list the names of warnings to throw on (e.g. --throw-warning=DeprecationWarning). I would also be happy with collapsing the 'deprecation' event back into 'warning'.

jasnell commented 8 years ago

Putting back on ctc-agenda so the additional concerns can be discussed.

Fishrock123 commented 8 years ago

@jasnell I figure one might want to ignore deprecations but sill receive other warnings of possible errors they may not know about.

If you're trying to ignore all warnings, there isn't much point in printing deprecations also though.

jasnell commented 8 years ago

Yep, ok, so let's sketch this out a bit... Perhaps something this:

What do you think?

jasnell commented 8 years ago

rebased and updated to address conflicts...

Fishrock123 commented 8 years ago

I'm actually not sure if it is good to merge the flags. Clarity, ease of use, backwards compat, etc.

I think I would be most comfortable with having both flags under what I outlined above.

jasnell commented 8 years ago

@Fishrock123: Ok, so to make sure I understand the flow you have in mind (please correct me if this is wrong):

Fishrock123 commented 8 years ago

@jasnell Correct. Also, --no-deprecation would mean only the deprecation event and deprecations printed to console would be suppressed.

jasnell commented 8 years ago

that works for me. @dougwilson ... any thoughts on that revised approach?

jasnell commented 8 years ago

@Fishrock123 ... one additional point: currently --throw-deprecation will only throw when one of Node.js' deprecated APIs are used. It will not throw if someone does a process.emitWarning() with a custom userland DeprecationWarning. Should we make it so that --throw-deprecation also throws on custom deprecations?

jasnell commented 8 years ago

@Fishrock123 ... ok, added a new commit that implements the revised flow. Per my last comment, I went ahead and made it so that any DeprecationWarning sent to process.emitWarning() would trigger a throw if --throw-deprecation is used.

jasnell commented 8 years ago

@Fishrock123 ... if you're good with this modified version, we may be able to pull this back off the ctc agenda and save everyone some time :-)

jasnell commented 8 years ago

this was discussed again on the CTC call. It was decided that dropping the deprecation event would be ideal and just keep everything through one warning event. Everything else would remain the same as currently implemented. I will be updating the PR, updating the summary of the functionality, and the CTC will discuss one more time before landing.

jasnell commented 8 years ago

@nodejs/ctc ... per the discussion today, here's the rundown of the current implementation:

The following additional semantics apply specifically to deprecations and exist to maintain backwards compatibility:

To be clear:

Note that this currently only impacts warnings and messages printed in JavaScript. It has no effect on outputs generated by the Node native src in `src/.cc`*

Examples:

$ node
> process.emitWarning('a simple warning');
undefined
> (node:97318) Warning: a simple warning
$ node --no-warnings
> process.emitWarning('a simple warning');
undefined
$ node --trace-warnings
> process.emitWarning('a simple warning');
undefined
> (node:97323) Warning: a simple warning
    at repl:1:9
    at REPLServer.defaultEval (repl.js:260:27)
    at bound (domain.js:281:14)
    at REPLServer.runBound [as eval] (domain.js:294:12)
    at REPLServer.<anonymous> (repl.js:429:12)
    at emitOne (events.js:96:20)
    at REPLServer.emit (events.js:183:7)
    at REPLServer.Interface._onLine (readline.js:216:10)
    at REPLServer.Interface._line (readline.js:555:8)
    at REPLServer.Interface._ttyWrite (readline.js:832:14)

(Using --no-warnings emits the 'warning' event, but turns off the default output)

$ node --no-warnings
> process.on('warning', (warning) => console.log('A WARNING!'));
...
> process.emitWarning('a warning happened');
undefined
> A WARNING!

(The existing deprecation methods are modified to use 'warning' events under the covers)

$ node
> util.deprecate(() => {}, 'nope!')()
undefined
> (node:97334) DeprecationWarning: nope!

(If users really want to, they can emit DeprecationWarning warnings directly using process.emitWarning())

$ node
> process.emitWarning('a warning', 'DeprecationWarning');
undefined
> (node:97334) DeprecationWarning: a warning

(Listening for 'warning' events is simple. The warning is delivered as an Error object)

$ node
> process.on('warning', (warning) => {
... console.log(warning.name);
... console.log(warning.message);
... console.log(warning.stack);
... });
...
Fishrock123 commented 8 years ago

The more I think about it, the more I think potential use-cases could only be fully solved by having a full middleware-like system. That would be too complex though.

Fishrock123 commented 8 years ago

@dougwilson how do you feel about this?

jasnell commented 8 years ago

@Fishrock123 ... definitely think that's way too complex. There would be nothing stopping someone from adding their own 'warning' handler that does more complicated things if they so desired.

jasnell commented 8 years ago

@Fishrock123 ... fixed! PTAL

Fishrock123 commented 8 years ago

Ok, I just want to hear back from doug before signing off so that we aren't disregarding anything / too much. :s

dougwilson commented 8 years ago

Following the discussion and I just read through the changes in the pull request and I don't have any objections.

jasnell commented 8 years ago

@Fishrock123 .. good to go now?

jasnell commented 8 years ago

@Fishrock123 ... rebased following your node.js refactoring. Looking good?

jasnell commented 8 years ago

@nodejs/ctc ... just a reminder, this is on the ctc-agenda again today for a final decision. Please review https://github.com/nodejs/node/pull/4782#issuecomment-197704962 for details on how this works.

Fishrock123 commented 8 years ago

Needs cli options added to doc/api/cli.markdown

@jasnell LGTM otherwise, I'll be around to sign off once these are fixed so you should be able to merge today.

Does this still need to be ctc-agenda?

jasnell commented 8 years ago

@rvagg had asked for another week to review just to make sure. It would be good to at least make sure there are no objections.

jasnell commented 8 years ago

@Fishrock123 ... updated!

Fishrock123 commented 8 years ago

CI: https://ci.nodejs.org/job/node-test-pull-request/2046/

As a note, I'll probably open a PR after this lands moving the warnings stuff to a new file (if it isn't here).

jasnell commented 8 years ago

oh, heh, was going to do that but got sidetracked. I can do that.

jasnell commented 8 years ago

@Fishrock123 .. ok separated!

Fishrock123 commented 8 years ago

LGTM :ship: (After the ctc-meeting I guess)

jasnell commented 8 years ago

There were no objections raised on the CTC call. Giving this about 24 hours for any additional comments. Will land tomorrow afternoon.

jasnell commented 8 years ago

Commits squashed. One final CI run before landing: https://ci.nodejs.org/job/node-test-pull-request/2059/

jasnell commented 8 years ago

Landed in c6656db. Thank you all!

boneskull commented 6 years ago

@jasnell Why is process.emit('warning') called on next tick (by default)?

jasnell commented 6 years ago

Just to keep the processing of the event from negatively impacting the primary sync code flow... just defers it a bit.