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

Improvement of CLI logging and error messages related to reflection. #1602

Closed
wants to merge 10 commits into from
Closed

Improvement of CLI logging and error messages related to reflection. #1602

wants to merge 10 commits into from

Conversation

Lur1an
Copy link
Contributor

@Lur1an Lur1an commented Nov 15, 2022

Adresses/Fixes #1593, #1594.

Implements

  • ExceptionHandler for CLI
  • Fixes for logging-level
  • Clearer Exception/Error messages regarding reflection errors

@devonfw/cobigen

- Fixed log-level settings for CLI
- Stacktrace for exception only printed in -v mode
- Rework of ValidationUtils, execution is not interrupted by exception, instead boolean value is returned
- Uncaught exceptions in CLI execution are manually handled with a ExecutionExceptionHandler to improve logging
- Added detail to exception messages connected to reflection issues
Zylesto
Zylesto previously approved these changes Nov 16, 2022
@Lur1an Lur1an requested a review from EduardKrieger November 17, 2022 09:08
path, triggerInterpreter, e);
LOG.warn("While reading the input {} with the inputreader {}, an exception occured: {} Trying next input reader...",
path, triggerInterpreter, e.getMessage());
if (LOG.isDebugEnabled()) e.printStackTrace();
Copy link
Member

Choose a reason for hiding this comment

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

Don't print stacktraces on your own, pass the e on case of debug as last log parameter

for (int i = 0; i < report.getErrors().size(); i++) {
RuntimeException e = report.getErrors().get(i);
LOG.error("Error: {}", e.getMessage());
if (LOG.isDebugEnabled()) e.printStackTrace();
Copy link
Member

Choose a reason for hiding this comment

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

Don't print stacktraces on your own, pass e on debug as last parameter on log function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in next commit.

// Log exceptions for devs in DEBUG
for (int i = 0; i < report.getErrors().size(); i++) {
RuntimeException e = report.getErrors().get(i);
LOG.error("Error: {}", e.getMessage());
Copy link
Member

Choose a reason for hiding this comment

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

Don't print messages of exceptions. They will be in the stacktrace anyhow

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The error message from the exception might contain useful hints for the user on how to fix it himself. My idea was to move the stacktrace of the exception into DEBUG but keep the exception message.

@@ -73,8 +73,14 @@ public void process(TextTemplate template, Map<String, Object> model, Writer out
env.setLogTemplateExceptions(false); // no duplicate logging
env.process();
} catch (TemplateException e) {
String detailedCause = "";
if (e.getCause().getClass().getCanonicalName().contains("java.lang")) {
Copy link
Member

Choose a reason for hiding this comment

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

Just getting the first cause is maybe not what you want. Most probably you want to look at the root cause wouldn't you?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True! Next commit extracts the rootcause before building error message.

String detailedCause = "";
if (e.getCause().getClass().getCanonicalName().contains("java.lang")) {
detailedCause = ". A problem with Reflection has likely occurred: "
+ e.getCause().toString()
Copy link
Member

Choose a reason for hiding this comment

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

Never log an exception to string. That's most often resulting in garbage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seemed like a quick way to get both the canonical type of the exception and the message into one String. I rewrote the extraction manually.

- Removed the printStackTrace and instead split the debug statements into 2 depending on LOG.isDebugEnabled()
- Fixed some whitespace issues
- Fixed formatting
- Extract root cause of exception in FreeMarkerTemplateEngine.java and build detailed message without directly using .toString() on the exception
@jan-vcapgemini jan-vcapgemini self-assigned this Dec 2, 2022
- removed concatenation from added LOG statements
LOG.debug("Cobigen exited with exception: ", e);
} else {
LOG.error("An error occurred while executing CobiGen: {}", e.getMessage());
}
Copy link
Member

Choose a reason for hiding this comment

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

That's a strange pattern. Normally you would expect that enabling debug log level, just logs come in addition. In this case, you would end up in a situation, that logs, which you have seen on INFO log will vanish. That's an unexpected behavior, which would result in confusion during log debugging.

I would propose to do something like this:

LOG.error("An error occurred while executing CobiGen: {}", e.getMessage(), (LOG.isDebugEnabled() ? e : null));

This would log the exception just in case you have debug log enabled, but it would keep the actual log message, so you will find the same log in both cases (INFO log as well as DEBUG log level).

Nontheless, there is one critical question here. Do we expect proper messages here? Do we throw proper exceptions with proper message, which give enough value at this point to guide / help the user? Or is this exception case here more about exceptions, we would not expect? If it's the latter, then I think it does not make any sense to distinguish debug log. If it's about exceptions only, which we would not expect, then we should always log the exception. But if we expect a lot of proper exceptions, which we throw on our own with proper messages, then the compressed solution as proposed is totally fine.

} else {
throw new CobiGenRuntimeException("Generation failed. Enable debug mode to see the exceptions occurred.",
report.getErrors().get(0));
LOG.error("Error: {}", e.getMessage());
Copy link
Member

Choose a reason for hiding this comment

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

Same as above, that's actually an antipattern do provide different logs in different levels.

Throwable rootCause = e;
while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
rootCause = rootCause.getCause();
}
Copy link
Member

Choose a reason for hiding this comment

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

exception causes are recursively defined, meaning, you will not be able to get the root cause here. There is an Exception Util, which could be used to properly give you some better information.

// Only logs message as possible hint for user
LOG.warn("While reading the input {} with the inputreader {}, an exception occured: {} Trying next input reader...",
path, triggerInterpreter, e.getMessage());
}
Copy link
Member

Choose a reason for hiding this comment

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

again anti-pattern, see above

@Lur1an Lur1an closed this by deleting the head repository Jan 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CobiGen CLI does not generate properly from non-build Java sources
6 participants