-
Notifications
You must be signed in to change notification settings - Fork 696
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
Use stderr for Cabal's diagnostic messages instead of stdout #4789
base: master
Are you sure you want to change the base?
Conversation
@Rufflewind, thanks for your PR! By analyzing the history of the files in this pull request, we identified @dcoutts, @ezyang and @phadej to be potential reviewers. |
Does this only affect |
It should affect everything, since I rewired all the I personally only care about #4652 in relation to Not really sure what could be done about the need for process-1.2.1.0, short of falling back to using stdout if process-1.2.1.0 is unavailable. |
Stack switched to sending most output to stderr pretty early on, some discussion here - commercialhaskell/stack#604 commercialhaskell/stack#446 . It's worked out well so far, the primary motivation is to distinguish output you might want to handle programmatically from output that's purely intended to be diagnostic, read by humans. I think is true to the intent of stdout / stderr, or at least what it means these days - the "err" in stderr is a bit of a misnomer. See https://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout |
@mgsloan coincidentally, since I wrote that comment I investigated the topic a bit, and I come to a similar conclusion. And for things like |
Having to special-case stuff like For such corner cases, my preference in is to decide either on stderr or stdout and stick with that. |
@Rufflewind Have you also tried grepping for |
@mgsloan I think it's more that the distinction between stdout/stderr never made sense in the first place. It obviously only works in extremely simplistic scenarios and is pointless for anything beyond that. (Hence, exit codes and the like. Why have a secondary signaling mechanism if stdout/stderr was a thing you could rely on? It's absurd and pointless. Slitting the output into two streams only leads to race conditions, etc.) |
@hvr I removed the dependency on process-1.2.1.0. Turns out @23Skidoo: Went through each of them again; see updated commit. The following files were not changed because:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks OK overall modulo some comments, my only concern is handling of corner cases like --dry-run
that @hvr mentioned. We will probably have to identify them one by one and manually switch to use stdout (maybe conditionally).
@@ -131,7 +133,8 @@ genBounds verbosity packageDBs repoCtxt comp platform progdb mSandboxPkgInfo | |||
verbosity packageDBs repoCtxt comp platform progdb | |||
mSandboxPkgInfo globalFlags freezeFlags | |||
|
|||
putStrLn boundsNeededMsg | |||
hPutStrLn stderr boundsNeededMsg | |||
hFlush stderr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, why do you need to flush stderr
? Isn't one of the points of stderr
is that it's unbuffered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it as a precaution because I saw stdout
being used a few lines later. I've removed it.
I think I saw stderr being set to line-buffered in the code somewhere, but I don't know for sure. But if that is the case then the flush shouldn't be needed.
@@ -54,7 +55,7 @@ runLogProgress verbosity (LogProgress m) = | |||
} | |||
step_fn :: LogMsg -> NoCallStackIO a -> NoCallStackIO a | |||
step_fn doc go = do | |||
putStrLn (render doc) | |||
hPutStrLn stderr (render doc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be replaced with notice
as well, I think...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted this particular change. Changing runLogProgress.step_fn
to use notice
instead of hPutStrLn
breaks too many tests as notice
will wrap the messages with -----BEGIN CABAL OUTPUT-----
markers, causing them to get caught in the test output.
@@ -281,7 +281,8 @@ ghcInvocation :: ConfiguredProgram -> Compiler -> Platform -> GhcOptions | |||
-> ProgramInvocation | |||
ghcInvocation prog comp platform opts = | |||
(programInvocation prog (renderGhcOptions comp platform opts)) { | |||
progInvokePathEnv = fromNubListR (ghcOptExtraPath opts) | |||
progInvokePathEnv = fromNubListR (ghcOptExtraPath opts), | |||
progInvokeOutAsErr = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only do this for GHC? Perhaps it should be the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure. Do these other programs write non-essential messages to stdout? I think the use of stdout for progress messages as GHC does is not normal, but I suppose Cabal could be proactive and force everything to stderr.
CI failure is due to |
Removed redundant imports. |
Looks like this PR breaks a whole load of tests, which I guess is expected -- the test suite expects the output to be on stdout. |
I recently ran into an annoyance where
I was able to work around it, but it would be nice if Cabal sent output like that to STDERR instead. Is this PR the best chance for that happening? Should I follow any other issues or PRs? |
Send all diagnostic messages (including debug, info, notice) to stderr instead of stdout. Likewise, redirect GHC's stdout to stderr as GHC sends progress output to stdout due to GHC Trac haskell#3636.
All tests pass now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the problem is that v2-run
may output something to stdout
, then this is no solution? What if I need to capture stderr
of program I v2-run
?
The only solution is to make -vsilent
truly silent (i.e. changing manual putStrLn
s to primitives in Verbosity
), use verboseUnmarkOutput
where appropriate to not break tests.
In that case, the stderr may contain messages from Cabal as well. This is reasonable because there is no general expectation that the contents of stderr has any structure. stderr is normally meant for human consumption; this contrasts with stdout, which may contain structured data or other outputs that the user intend to capture or forward to another program. It is uncommon to capture stderr and also to expect the same degree of structure as captured stdout.
That is a separate and orthogonal issue. This PR is only intended to address the issue in which Cabal writes unstructured diagnostic messages to stdout. Making Cabal truly silent is not without downsides, such as the inability for Cabal to return useful diagnostics to the user when something goes wrong. Some CLI tools (e.g. |
I've been annoyed by "Up to date" or build messages from cabal. I agree that making it completely silent is a separate issue; I do want to see errors from cabal if something went wrong. |
Marking this PR as draft 🙂 |
Please include the following checklist in your PR:
[ci skip]
is used to avoid triggering the build bots.Manually tested on a minimal Cabal project.
cabal build 2>/dev/null
shows nothing.Fixes #4652.