-
Notifications
You must be signed in to change notification settings - Fork 70
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
Improvement of CLI logging and error messages related to reflection. #1602
Conversation
- 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
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/CobiGenCLI.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/CobiGenCLI.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/GenerateCommand.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/CobiGenCLI.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/CommandCommons.java
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/GenerateCommand.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/GenerateCommand.java
Outdated
Show resolved
Hide resolved
...reemarker/src/main/java/com/devonfw/cobigen/tempeng/freemarker/FreeMarkerTemplateEngine.java
Outdated
Show resolved
Hide resolved
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(); |
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.
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(); |
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.
Don't print stacktraces on your own, pass e on debug as last parameter on log function
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.
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()); |
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.
Don't print messages of exceptions. They will be in the stacktrace anyhow
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.
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")) { |
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.
Just getting the first cause is maybe not what you want. Most probably you want to look at the root cause wouldn't you?
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.
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() |
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.
Never log an exception to string. That's most often resulting in garbage.
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.
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
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/CobiGenCLI.java
Outdated
Show resolved
Hide resolved
cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/GenerateCommand.java
Outdated
Show resolved
Hide resolved
- removed concatenation from added LOG statements
LOG.debug("Cobigen exited with exception: ", e); | ||
} else { | ||
LOG.error("An error occurred while executing CobiGen: {}", e.getMessage()); | ||
} |
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.
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()); |
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.
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(); | ||
} |
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.
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()); | ||
} |
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.
again anti-pattern, see above
Adresses/Fixes #1593, #1594.
Implements
@devonfw/cobigen