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

Implemented error console in JavaFX #1383

Merged
merged 15 commits into from
Sep 19, 2016
Merged

Implemented error console in JavaFX #1383

merged 15 commits into from
Sep 19, 2016

Conversation

motokito
Copy link
Contributor

@motokito motokito commented May 11, 2016

This is the error console in JabRef being implemented in JavaFX. The Console is highly flexible in positioning and styling its components through a fxml and corresponding css stylesheet.

Also to show better the error console content (Log, Output, Exception), i have allowed to resize error console windows manually.

error console dialog

PS:

  • update the error console screenshot
  • new feature:
  • Change in CHANGELOG.md described
  • Screenshots added (for bigger UI changes)

@tobiasdiez
Copy link
Member

Please also add a screenshot for these new javafx dialogs.
Moreover, it would be nice if you could address the issues #882, #872 (I think, this is already covered with this PR...in this case please add a changelog entry) and #819, which are all connected to the error console.

@Siedlerchr
Copy link
Member

Please adress the Language-key related errors, The first build failed because there were still some obsolete keys...

@matthiasgeiger
Copy link
Member

@tobiasdiez @Siedlerchr slowly, slowly... let the students check this PR first and wait until it is labeled with "ready-for-review" 😉

while (true) {
Thread.sleep(REFRESH_RATE);

// IMO this is a really, really bad way to do this, but a saw no other way since the stage is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: don't use a refresh thread but data binding.
So you add a property to ErrorConsoleViewModel to return a FX-observable list of output/errormessages which are always up-to-date and then bind the text property of the textarea to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how can i bind the observable list to this outputStream. The problem is that all output gets written to a stream which in my opinion is incompatibe with a observable List.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can register a custom PrintStream as a TeeStream, similar to what is done in

return new TeeStream(consoleOut, systemOut);
.
This custom PrintStream writes to a (observable) list.

new PrintStream(System.out) {
List<String> messages = new blabla();
@Override  
public void println(String s) {
    messages.add(s);
    super.println(s); //needed?
  }

@codecov-io
Copy link

codecov-io commented Jun 20, 2016

Current coverage is 28.39% (diff: 10.52%)

Merging #1383 into javafx will increase coverage by 17.61%

@@             javafx      #1383   diff @@
==========================================
  Files           705        705           
  Lines         46412      46332     -80   
  Methods           0          0           
  Messages          0          0           
  Branches       7637       7639      +2   
==========================================
+ Hits           5002      13154   +8152   
+ Misses        40963      32053   -8910   
- Partials        447       1125    +678   

Powered by Codecov. Last update bc6f0c9...9e9bbc2

@motokito
Copy link
Contributor Author

I am having trouble to hide the developer information. The css file probably needs some changes, I tried to set the visibilty but that didn't work out. @tobiasdiez Do you have some tips to handle this?

@tobiasdiez
Copy link
Member

tobiasdiez commented Jun 29, 2016

Sorry for my later answer. Normally you do this by using a PseudoClass inactive and change it with pseudoClassStateChanged, see for example https://github.com/JabRef/jabref/pull/1438/files#diff-9a2c5dd139caeeb5e3e3eebb9adb24b3R92. Then you can style them via .list-cell:active and .list-cell:inactive.

I would however only use the PseudoClasses for real styling purposes, for example .list-cell:error shows an error icon and sets the font color to red. Filtering should really happen on the basis of the viewmodel to which the listview binds (as you have done it right now).

For debugging UI issues, the tool Scenic View is very helpful (http://fxexperience.com/scenic-view/). I had some problems with running it separately and bind it to JabRef. However, adding it to the dependencies (Project Structure -> Modules -> Dependencies -> Add) and then invoke ScenicView.show(scene); somewhere works.


developerInformation.bind(developerButton.selectedProperty());
developerInformation.addListener((observable, oldValue, newValue) -> {
ObservableList<ObservableMessageWithPriority> emptyList = FXCollections.observableArrayList(Collections.EMPTY_LIST);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is no need to replace the items in allMessage, just use filteredData.setPredicate. Have a look at http://stackoverflow.com/questions/30915007/javafx-filteredlist-filtering-based-on-property-of-items-in-the-list

@motokito
Copy link
Contributor Author

motokito commented Jul 4, 2016

@tobiasdiez
I have created FilterList to filter messages. But I have one problem to view correctly entries in Listview (have a look at my Screenshot). It only runs correctly if entries run out of the Listview. I have created a Test Button to test this behavior. This Test Button generates 1 entry in System.out, throws 1 exception and generates 1 entry in the Cache. This will be removed later.
Can you help me and tell me, why Listview doesn't displays the entry correctly?

notcorrectview

@tobiasdiez
Copy link
Member

tobiasdiez commented Jul 4, 2016

Sorry but I don't understand where your problem is. It looks like it prints the Test Cache message as well as the (first line of) the error stack trace. The system.out is ignored as I would have expected since you hide low priority messages.

@motokito
Copy link
Contributor Author

motokito commented Jul 4, 2016

Hi @tobiasdiez ,
So i will explain you, what is my problem.

  • The ListView shoulds show you all log entries and other entries like system.out and exception, if the button "Development Information" disable.
  • If the button on click, it shoulds hide all system.out and exception entries.
    I have handle this will a filterlist. But the behavior by showing of entries is not correct.
  • Reproduct:
    • Start error console
    • Click on "Test" Button (1 time or more times)
    • Click on "Development Information" Button
    • Click on this again
      If you do so like i have written, then you will understand my problem.
      Sorry about my bad english. I hope that you understand what I mean. I need you help or some tipp how i can clear this problem :-)

Thx you

this.outStream = out2;
this.priority = priority;

}

public TeeStream(PrintStream out1, PrintStream out2) {
super(out1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call the other constructor using this(...) here.

@tobiasdiez
Copy link
Member

Thanks for the additional description. I added a comment to ErrorConsoleViewModel which should help you to solve the problem.

For the next time, please try to add some tests first. There were quite a few things which could have been wrong:

  • Are the messages correctly passed to the T-Stream?
  • Do they have the correct priority?
  • Is filtering of the list working properly?
  • And finally: is is just a problem with the way how messages are displayed in the list view.

The first 3 options could have been ruled out by automatic tests. It would be good if you could add corresponding tests (which also require some positve refactoring, like making filteredList a (public) class variable and moving its initialization to the constructor).

@motokito
Copy link
Contributor Author

motokito commented Aug 1, 2016

There are three solution for this problem with create issue function:

  • Solution 1: Using of a GitHub API to create issue directly from JabRef with log in data, which user not like to do it. But I think, that way will be nice solution and GitHub will get more member (take a look in create issue dialog screenshot).
    From customer: it will be nice this solution with a default account, but it will be not work.

create issue with github api

  • Solution 2: Using OAuth2 to create issue directly from JabRef without log in data, but the user must give the application access in their account to use it, That will be difficult for some user.
  • Solution 3 (This is my actual implement solution): Create issue over default browser with help of saved log and exception information in clipboard. (take a look in create issue pop up screenshot).

create issue with default browser

After close or click on OK Button. The default browser will open and show create issue site with default title (automatic bug report-"current time with this format yyyyMMddHHmmss") and a default issue description (JabRef version, operating system version, Java version). During the show of this create issue site, the log and exception information will be saved in clipboard. So the user can be paste it for detail information in issue description. (take a look in create issue in default browser with paste detail information screenshot)

new issue

@Braunch
Copy link
Contributor

Braunch commented Aug 1, 2016

Which one did you implement?

@tobiasdiez
Copy link
Member

I really like the copied-to-clipboard-solution. Its simple yet effective.

@Braunch Braunch changed the title [WIP] Implemented error console in JavaFX Implemented error console in JavaFX Aug 8, 2016
@Braunch Braunch changed the title Implemented error console in JavaFX [WIP] Implemented error console in JavaFX Aug 8, 2016
@Siedlerchr
Copy link
Member

Siedlerchr commented Aug 15, 2016

Can you please post a new screenshot of the actual look?
Edit// and could you please test the look on HIDPI screens,too?

this.message = message;
}

public void setIsFiltered(boolean isFiltered) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still used?

@tobiasdiez
Copy link
Member

Thanks for the update. The code looks better now. I have just a few more remarks, then this can be merged. @koppor pls do the final review

/**
* This LogMessage will be save all message entries in a ListProperty.
* <p></p>
* This list will be use late in ErrorConsoleViewModel to filter message after their priority
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix English. Proposal:

This call saves all messages in a list. The list is used in ErrorConsoleViewModel to filter messages according to their priority.

@motokito
Copy link
Contributor Author

motokito commented Sep 8, 2016

@tobiasdiez @koppor: feedbacks are done. Only this teestream thing, i am not sure how to fix it 😄

@koppor
Copy link
Member

koppor commented Sep 8, 2016

Maybe someone else from @JabRef/stupro can help. @bartsch-dev maybe? It's a kind of architectural decision.

@tobiasdiez
Copy link
Member

Try to use StreamEavesdropper instead of TeeStream

@boceckts
Copy link
Contributor

@tobiasdiez Is this what you meant with moving the code to the streamEavesdropper?

super.write(buf, off, len);
String s = new String(buf, off, len);
addToLog(s, MessageType.EXCEPTION
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting.

);
}
};
return new TeeStream(consoleErr, systemErr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand it correctly, then everything from systemErr is also written to consoleErr. With your implementation all messages to consoleErr are posted to the cache (addToLog).
So far so good. But they also get posted as well as to the underlying errByteStream, which is no longer required (is it?). Thus could you remove the byte stream part?

@tobiasdiez
Copy link
Member

Yes this looks better.
So now I had a look at the code. If I understand it correctly, then there already exist two ways of listen to logger messages:

  • GuiAppender: listens to everything which goes through the Log4j API (i.e. LOGGER.log(...)) and writes it to Cache
  • StreamEavesdropper: listens to everything which goes through the System streams (System.out/err) and writes it to some streams

And you added:

  • LogMessages: listens to everything and writes it some some internal list

Could you refactor the code so that everything is only written ̀to the internal list of LogMessages, i.e. get rid of the Cache class and the printstreams in StreamEavesdropper. (And please add code comments to the classes, it was hard to understand what they actually do)

Appendum for myself:
Since there is essentially no code which still uses System.out/err.printLn, I would actually try to get rid of the StreamEavesdropper completely. Only problem: uncaught exceptions are not written via the Log4j interface. But this could be solved by setting the default handler.

* <li>MessageType.EXCEPTION is define for exception entries
* </ul>
*/
public class LogMessage {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace this class by org.apache.logging.log4j.core.LogEvent and Log4jLogEvent.newBuilder().setMessage(message).build() if you need to convert a string to the LogEvent.

@motokito
Copy link
Contributor Author

@tobiasdiez I have refactored and have done feedback. Hope it will be merged this time 😄

Copy link
Member

@tobiasdiez tobiasdiez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite mergable but only a few final remarks. Good work.

@@ -59,12 +66,14 @@ public void show() {
errorConsole.setDialogPane(pane);
errorConsole.setResizable(true);
errorConsole.show();
Log log = LogFactory.getLog(this.getClass());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was for test purposes, right? Please remove it.

setText(logMessage.getMessage().toString());

Level prio = logMessage.getLevel();
if (prio.equals(ERROR)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls use a switch statement here and show an info by default (instead of nothing with null/null)

* @param message message of log event
* @param priority level of log event
*/
private void addToLog(String message, Level priority) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go through the code that all priority and prio are properly renamed to level.

// stack traces logged by 'Log.error("message"), e' will be split by new lines so we can create a new log event for each line as 'e.printStackTrace()' would do.
if (event.getLevel() == Level.ERROR) {
Arrays.asList(message.split("\n")).stream().filter(s -> !s.isEmpty()).forEach(log -> {
LogEvent messageWithPriority = Log4jLogEvent.newBuilder().setMessage(new SimpleMessage(log.replace("\n", ""))).setLevel(event.getLevel()).build();
Copy link
Member

@tobiasdiez tobiasdiez Sep 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this kind of message-rework really necessary?
I had the hope that here a simple LogMessages.getInstance().add(event) would satisfy and then maybe use event.getMessage().getFormattedMessage() in the view (d6c8eb1#diff-d08231c1b1e93f3d52d35f72f3b55821R112).

If this is not possible, please move the code to the view, i.e. determine there how a LogEvent should be displayed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tobiasdiez if i don't split this it will be show me not so nice in list view. It looks like this, because in append-method of GuiAppender I get only one LogEvent entry with all information by insert a log entry like Log.error (e). It is not like System.err:

2016-09-19_07h12_28
And if i don't replace System.lineseparator with "" then i will get 2 line each list cell.

That is the reason, why i have reformat this log event entry. That look better. 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. What happens if you use setText(logMessage.getMessage().getFormattedMessage()) to show the message instead of setText(logMessage.getMessage().toString()) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tried it, but i get the same effect like that screenshot 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then keep your code but move it to the view if this is possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I have tried it, but it doesn't let me extract to view. 😢. Other feedback I have done it 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then we leave it like that for the moment and maybe fix it later.

@tobiasdiez tobiasdiez merged commit 424cde8 into JabRef:javafx Sep 19, 2016
@motokito motokito deleted the ErrorConsoleDialogFX branch September 21, 2016 12:01
@koppor koppor mentioned this pull request Oct 29, 2016
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants