elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.65k stars 299 forks source link

Add a print function that prints to stderr #1777

Open dann-merlin opened 6 months ago

dann-merlin commented 6 months ago

What new feature should Elvish have?

This is probably a question of taste, but I think builtin print-to-stderr functions would be useful.

I know that I can just pipe the output of print or echo to stderr and that I can just write such a function myself. However, I think for scripting in particular this would be a great addition, as printing errors is something that is very commonly done and having a shortcut like this would make it a bit less tedious.

It would probably be sensible to add error versions for the three main printing functions.

Here are some proposals how these functions can be called. I personally like the err-suffix most.

original e-prefix err-prefix e-suffix err-suffix
print eprint errprint printe printerr
printf eprintf errprintf printfe printferr
echo eecho errecho echoe echoerr

These functions should maybe also automatically style the output in red (or maybe only in the case of echo, idk).

I would also be open to implement this my self, if there's interest in this. While I don't really have experience with go, I don't think this should be too hard.

Output of "elvish -version"

0.20.1+archlinux4

Code of Conduct

xiaq commented 6 months ago

(Elvish doesn't have fprint, I think you misspelt printf? Also errecho and eecho seems transposed - that's not important though.)

I'm not sure about this. I agree with you that printing to stderr is common enough in shell scripts and it may warrant a bit of special treatment. But I feel that there's a bigger problem about providing feedback to the user and logging in general, and providing a parallel stderr version for echo, print and printf is only scratching at the surface. I don't have a clear definition to that problem or a clear solution in mind, so I'll need to think more about this.

Re naming, I'd go with the -err suffix with a dash, so print-err, printf-err and echo-err.

dann-merlin commented 6 months ago

Ah, yes. I fixed the misspelling and switch-up.

Maybe elvish could have a log module, similar to python's logging module? In that case it might look like this:

log:error some error log:warn some warning log:info some info log:debug some debug info

by default these functions would have a default output file(descriptor), but they could also be configured to behave differently. Also they might have some default style which could be changed as well.

About the other issues with these functions: Have you put them into words somewhere yet?

xiaq commented 6 months ago

A log module with a runtime-configurable destination and style is definitely a reasonable building block, and it does make the need for separate stderr-writing commands obsolete.

The API is orthogonal to the echo/print/printf dimension though. Which one does log:error behave like?

There are some more high-level questions I'd like to have answered:

I think traditional logging libraries are fairly unopinionated in that they don't really answer these questions and just give you APIs to do whatever you prefer. Elvish should probably have an unopinionated logging library as a foundation but since shells are more in the business of "applications" I feel there needs to be either a more opinionated high-level library or at least a pattern.

(Another question is when multiple libraries use the logging library, how would the logging library know the source of each log message. This is a more technical question though, so no need to delve on it too much for now.)

dann-merlin commented 6 months ago

These are some tough questions...

Sometimes an application might just want to print an error/warning to stderr without failing, if e.g. some parsed file does not look like it should, but the application can handle that and just keep going. In this case log:error would be appropriate.

I think the application user should probably be able to control the log level of an application (including its libraries). However an application may want to disable all logging output for a library, because it e.g. would generate very noisy logs otherwise. This on the other hand might be exactly what the user wants.

I think the best compromise might be that there's a variable LOGLEVEL which states the general preference of the user and some other way to somehow overwrite the loglevel an application set for an imported library.

I'm not sure what would be the most sensible way of doing this tough. Here are some ideas:

  1. specific loglevel variables for libraries: If the user wants to see debug output for a fictional ffmpeg module a script might import, they could set LOGLEVEL_<module-name>=debug so LOGLEVEL_ffmpeg=debug or maybe something like: LOGLEVEL_OVERWRITE=ffmpeg:debug
  2. general forcing of user specified loglevel This approach would not have such a fine-grained control, but would be a little simpler. Instead of LOGLEVEL, the user might alternatively (LOGLEVEL would the be ignored) specify FORCED_LOGLEVEL=debug which would force the loglevel for all modules to be the one specified by the user.

I think I would prefer the first approach, but the second one might also be preferable due to its simplicity.

I'm not sure if there really is a need for a more opinionated high-level library. I could maybe think of a echo-err or only err(or) which would really just be a call to log:error including some formatting like a timestamp and the location (i.e. line of code + srcfile). Would that be kind of what you mean by "opinionated high-level library"?

Oh, also: when talking about these variables I had environment variables in mind, but they could (and in the case of elvish probably should) of course also be variables in a module in which case the naming would obviously be a bit different. Edit: I'm not sure how a user calling an elvish script from another shell would set these variables without environment variables though.

krader1961 commented 5 months ago

Note that there are a large number of commands that produce output on the byte stream; e.g., to-lines. We probably do not want special cases of all those commands and it is unclear why commands like print and echo should have stderr variants while to-lines does not. There is also the potential for unexpected mistakes; e.g., echo-err hello | from-lines would not pipe the "hello" text to the from-lines command. As established earlier in this issue what would be more useful is an Elvish logging module that would take care of things like (optionally) time-stamping a message and provide context for where the message was emitted. Possibly also providing different behavior depending on whether the output destination was a tty or not.