Skip to content
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

Restricting command line output to one line #705

Open
eugenepeh opened this issue May 24, 2019 · 12 comments
Open

Restricting command line output to one line #705

eugenepeh opened this issue May 24, 2019 · 12 comments

Comments

@eugenepeh
Copy link
Member

eugenepeh commented May 24, 2019

The console output too much messages; making it difficult to differentiate important messages.

Hence, we should restrict the status message from occupying too many lines on the terminal screen, making it self contained in a single line by overwriting itself.

@jinyao-lee
Copy link
Contributor

I don't know if there's a way to overwrite the same line using logging.. AFAIK, there's no way to overwrite to same line using logging

@eugenepeh
Copy link
Member Author

The logging can be reimplemented if such feature does not exist; can even write our own API too if we have to as it also provides us with greater control.

@damithc
Copy link
Collaborator

damithc commented May 29, 2019

Alternatively, we can try to format the output such that important messages are hard to miss.
Overwriting has the downside that we lose the ability to see the sequence of events that happened before.

@eugenepeh
Copy link
Member Author

eugenepeh commented May 29, 2019

Alternatively, we can try to format the output such that important messages are hard to miss.

The intention is to make it less important message to take up less space though.
E.g. if we use RepoSense to analyze 50+ repos, its going to flood the CLI with bunch of messages, which can be tedious to scroll through all of them for the error messages.

So my suggestion is to have the info messages to always overwrite itself, leaving the error messages right on top of it.

E.g.

[ERROR] ...
[ERROR] ...
[INFO] ... this should always takes up only one line which inform user purely about the progress ...

If the following line is going to be another error message, delete the last [INFO] line, output the new [ERROR] message, then prints the next [INFO] line again.

Overwriting has the downside that we lose the ability to see the sequence of events that happened before.

If the user wants to keep all the messages, we can add in a verbose flag afterward to disable the overwriting.
Otherwise, the log file would've contain all the necessary info in chronological order as well, in the event we need to debug the error that has occurred.

@bluein-green
Copy link
Contributor

I came up with something like this:

terminal_v3

Specifically, I did this in CustomLogFormatter#format, that is used by the console handler:

if (record.getLevel().equals(Level.INFO)) {
    builder.append("\r");
    builder.append("\u001b[1000D");
    builder.append("\u001b[K");
    builder.append(dateFormat.format(new Date(record.getMillis()))).append(" - ");
    builder.append(formatMessage(record))
} else {    // Level.WARNING and higher
    builder.append("\r");
    builder.append(dateFormat.format(new Date(record.getMillis()))).append(" - ");
    builder.append("\u001b[37;43m");
    builder.append("[ERROR]");
    builder.append("\u001b[0m");
    builder.append(" ");
    builder.append(formatMessage(record));
    builder.append("\n");
}

However, it is highly dependent on the width of the terminal because of using \r and \u001b[K to clear one line of printed output on the console for Level.INFO messages (and then print a new message in the same line). For smaller widths, I couldn't achieve the desired effect.

Also, there doesn't seem to be a platform-independent way to determine the width of the terminal in Java unless we want to include libraries (https://stackoverflow.com/questions/1286461/can-i-find-the-console-width-with-java). Finding the width would help to determine the number of lines a message occupies in the terminal.

Are there other ways of making Level.INFO messages (that may span multiple lines) overwrite each other?

@eugenepeh
Copy link
Member Author

However, it is highly dependent on the width of the terminal because of using \r and \u001b[K to clear one line of printed output on the console for Level.INFO messages (and then print a new message in the same line). For smaller widths, I couldn't achieve the desired effect.

For the width problem is it that if the newly printed line is shorter than the existing one, non-overwritten chars from previous line will remain?

@bluein-green
Copy link
Contributor

No - if all messages are short enough to fit in 1 line in the terminal, we can use the escape sequence \u001b[K to clear that line before printing a new, shorter message.

The issue is when some messages are long and occupy multiple lines in the terminal due to line wrapping.

Suppose a long message occupies 2 lines on the terminal due to line wrapping. The cursor will be at the 2nd line. Using \r and \u001b[K at the start of the next message results in the 2nd line being cleared, and that new message being printed in that line.

An example:
terminal_example

@eugenepeh
Copy link
Member Author

Hmm, maybe in that case, we could probably make our own print class?

Whenever a call is made to the print function, we will record the length of the text that will be printed. With that info, when we're going to overwrite the previous line, we can backspace that amount of time.

@bluein-green
Copy link
Contributor

Yes that would help with recording the number of lines the old message occupied.

To calculate the number of lines (length of message / width of terminal), we will need the width of terminal. However, this is rather difficult to determine unless we include a library (e.g. jline). I'm not sure about the impact of including the library on performance. Would it be advisable to do so?

@eugenepeh
Copy link
Member Author

If we do the backspace way, we wouldn't need to know the width of the terminal anymore, isnt it?
At the same time, this will resolve the difference between different platform too.

@bluein-green
Copy link
Contributor

Ah. Using backspace (\b) worked only for single line messages. For multi-line messages, backspaces only moves the cursor to the left margin, and thus the non-last lines will not get overwritten.

I also tried using saving/restoring the cursor position:

  1. Save position
  2. Clear rest of screen (cursor position and below)
  3. Print
  4. Restore position

but it doesn't work when the messages reach the bottom of the terminal and the terminal has to scroll.

@eugenepeh
Copy link
Member Author

Ah. Using backspace (\b) worked only for single line messages. For multi-line messages, backspaces only moves the cursor to the left margin, and thus the non-last lines will not get overwritten.

I guess this is also cause of the problem with your original solution; it does not have any concept of lines of text. In that case, we may have to restrict non-error messages to fit into single lines.

eugenepeh pushed a commit that referenced this issue Jul 14, 2019
Messages of different severity are outputed in similar format, without
any form of distinction.

This creates difficulty for our users to distinguish messages of
different severity from the logs. Moreover, messages of higher severity
often contains important info which may requires user's action and
shouldn't be left unnoticed.

Let's make these messages more distinct by inserting a highlighted
status tag e.g. `[ERROR]` before the message.
@dcshzj dcshzj moved this to Tasks on hold in RepoSense Roadmap Aug 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Tasks on hold
Development

No branches or pull requests

4 participants