I have a problem where the when clause of a drools rule throws a MethodNotFoundException. I'm looking for a way to figure out which rule it is during runtime to be able to remove it from the list of rules to use.
Rule Example
Rule "FooBar"
when
$V1 : Foo ( ) AND
$V2 : FooBar( ) from $V1.getGoodMethod() AND
$V3 : FooBarBar( status == "FooBar" ) from $V2.getBadMethod()
reply : FooFooBar()
then
reply.getList().add("FooBar");
end
So, the getBadMethod on FooBar doesn't exist. I would like a way of telling what rule it is, and removing it from the list of rules to use.
Tried and Failed Solutions:
I've tried extending the DefaultAgendaEventListener and overriding the beforeActivationFired method to add the rule being fired to a list. I was hoping the last one in the list would be the one that threw the error, but sadly it didn't work out that way.
I've now tried adding "always true" rules before all my rules. They log the name of the rule that comes after it. The problem being when there is an exception in the "WHEN" clause nothing gets logged. It's as if no rules get fired when an Exception such as the one above occurs.
The problem all lies with the dynamic drools generation code. I would like to take a two pronged approach of fixing the generation code, and catching exceptions like the one listed in this post.
Side note: I do check for errors in the builder. I receive no errors from the below code.
KnowledgeBuilderErrors errors = builder.getErrors();
if (!errors.isEmpty()) {
for (KnowledgeBuilderError error : errors) {
...
}
}
As per my understanding, before doing fireAllRules() method below steps should be followed:
Add rules to the Package / Knowledge Builder
Validate that there are no errors in the Rules
Inject Rules in the working memory
Of Course, it is possible to fireRules without Step 2, but this practice can result in problems as mentioned in this question.
If I were you, I would follow the below logic to fix your this issue:
Step 1:
private RuleBase initialiseDrools() throws IOException, DroolsParserException {
PackageBuilder packageBuilder = readRules();
return addRulesToWorkingMemory(packageBuilder);
}
Step 2:
private PackageBuilder readRules() throws DroolsParserException, IOException {
PackageBuilder packageBuilder = new PackageBuilder();
PackageBuilder intermPackageBuilder = null;
listOfReader = dynamicRuleReader(); // Here goes your application code
for(Reader reader : listOfReader){
try{
intermPackageBuilder = new PackageBuilder();
intermPackageBuilder.addPackage(reader);
assertNoRuleErrors(intermPackageBuilder); // This is the core step.
// Above line throws an exception, every time a rules fails. You can persist this exception for production debugging
packageBuilder.addPackage(reader);
}catch(DroolsParserException | IOException e){
logger.error("Rules contain error, so skip adding them to the Package Builder");
}
}
return packageBuilder;
}
Step 3:
public void shouldFireAllRules() throws IOException, DroolsParserException {
RuleBase ruleBase = initialiseDrools();
WorkingMemory workingMemory = ruleBase.newStatefulSession();
int expectedNumberOfRulesFired = 2; // Idealy this number should be equal to the number of total rules injected in the Working memory
int actualNumberOfRulesFired = workingMemory.fireAllRules();
assertThat(actualNumberOfRulesFired, is(expectedNumberOfRulesFired));
}
Using above method, you will not executing a rule that has errors, and the situation described above will not arise.
However, I still believe you should focus more on the piece of code that generate erroneous Rules, and the method described above only to track and persist such occurrences.
Related
void appendFile() throws IOException{
FileWriter print = new FileWriter(f, true);
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
print.flush();
print.close();
}
boolean fileExist(){
return f.exists();
}
try{
if (f.fileExist())
f.appendFile();
else {
throw new IOException();
}
}
catch(IOException e) {
e.printStackTrace();
}
I'm not sure if the ecxeption is well handeled? The FileWriter is not going to be created if there is a fileNotFoundException, therefore don't need to be closed. However, is it possible that this code throws another kind of IOException after the file was opened?, and in that case do I need a finally block to close the file.
No.
It doesn't safely close the resource
The general rule is, if you call a constructor of an object that represents a closable resource, or a method that returns one which documents that this counts as 'opening the resource', which often but not always includes new being part of the method name (examples: socket.getInputStream(), Files.newInputStream), then you are responsible for closing it.
The problem is, what if an exception occurs? So, you have to use try/finally, except that's a mouthful, so there's a convenient syntax for this.
The appendFile method should use it; it isn't, that makes it bad code. This is correct:
try (FileWriter print = new FileWriter(f, true)) {
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
}
Not how it is not neccessary to flush before close (close implies flush), and in this case, not neccessary to close() - the try construct does it for you. It also does it for you if you get out of the {} of the try via a return statement, via control flow (break), or via an exception, or just by running to the } and exiting normally. No matter how - the resource is closed. As it should be.
It throws description-less exceptions
else throw new IOException(); is no good; add a description that explains why the exception happened. throw new IOException("File not found") is better, but throw new FileNotFoundException(f.toString()) is even better: The message should convey useful information and nothing more than that (in other words, throw new IOException("Something went wrong") is horrible, don't do that, that message adds no useful information), should not end in punctuation (throw new IOException("File not found!") is bad), and should throw a type that is most appropriate (if the file isn't there, FileNotFoundException, which is a subtype of IOException, is more appropriate, obviously).
It commits the capital offense
You should not ever write a catch block whose contents are just e.printStackTrace();. This is always wrong.
Here's what you do with a checked exception:
First, think of what the exception means and whether the nature of your method inherently implies that this exception can occur (vs. that it is an implementation detail). In this case, you didn't show us what the method containing that try/catch stuff even does. But let's say it is called appendFile, obviously a method that includes the text 'file' does I/O, and therefore, that method should be declared with throws IOException. It's not an implementation detail that a method named appendFile interacts with files. It is its nature.
This is somewhat in the eye of the beholder. Imagine a method named saveGame. That's less clear; perhaps the mechanism to save may involve a database instead, in which case SQLException would be normal. That's an example of a method where 'it interacts with the file system' is an implementation detail.
The problem that the exception signals is logical, but needs to be more abstract.
See the above: A save file system can obviously fail to save, but the exact nature of the error is abstract: If the save file system is DB-based, errors would show up in the form of an SQLException; if a file system, IOException, etcetera. However, the idea that saving may fail, and that the code that tried to save has a reasonable chance that it can somewhat recover from this, is obvious. If it's a game, there's a user interface; you should most absolutely TELL the player that saving failed, instead of shunting some stack trace into sysout which they probably never even look at! Telling the user that something failed is one way of handling things, not always the best, but here it applies).
In such cases, make your own exception type and throw that, using the wrapper constructor:
public class SaveException extends Exception {
public SaveException(Throwable cause) {
super(cause);
}
}
// and to use:
public void save() throws SaveException {
try {
try (OutputStream out = Files.newOutputStream(savePath)) {
game.saveTo(out);
}
} catch (IOException e) {
throw new SaveException(e);
}
}
If neither applies, then perhaps the exception is either essentially not handleable or not expectable or nearly always a bug. For example, writing to an outputstream that you know is a ByteArrayOutputStream (which can't throw), trying to load the UTF-8 charset (which is guaranteed by the JVM spec and therefore cannot possibly throw NoSuchCharsetException) - those are not expectable. Something like Pattern.compile("Some-regexp-here") can fail (not all strings are valid regexps), but as the vast majority of regexes in java are literals written by a programmer, any error in them is therefore neccessarily a bug. Those, too, are properly done as RuntimeExceptions (which are exceptions you don't have to catch or list in your throws line). Not handleables are mostly an application logic level thing. All fair game for runtimeexceptions. Make your own or use something that applies:
public void save(int saveSlot) {
if (saveSlot < 1 || saveSlot > 9) throw new IllegalArgumentException("Choose a saveslot from 1 to 9");
// ... rest of code.
}
This really feels like door number one: Whatever method this is in probably needs to be declared as throws IOException and do no catching or trying at all.
Minor nit: Uses old API
There's new API for file stuff in the java.nio.file package. It's 'better', in that the old API does a bunch of bad things, such as returning failure by way of a boolean flag instead of doing it right (by throwing an exception), and the new API has far more support for various bits and bobs of what file systems do, such as support for file links and creation timestamps.
The project I'm working on uses Esper to create monitoring rules. These rules are either active or inactive, based on a boolean in the SQL row. I would like to set up a check to see if there are any new active rules, create a statement from the, and add them to a hashmap. This will periodically run using Spring scheduler. The code so far looks like this:
private void refreshStatement(Rule rule) throws Expression {
List<String> allRules = dao.getAllRules();
for (String rule : allRules) {
EPStatement statement = epService.getEPAdministrator().createEPL(rule);
statement.addListener(new RuleListener(rule));
ruleMap.put(rule.getId(), statement);
}
}
On the initial run, this works fine. The statements are generated and added to the hashmap ruleMap. Upon the method running a second time due to the scheduler, though, it fails due to the first rule it sees already existing. For example:
ERROR [2018-08-14 12:00:00,000] org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler: Unexpected error occurred in scheduled task.
! com.espertech.esper.epl.expression.core.ExprValidationException: Context by name 'Test_Case' already exists
Is there any good way to check to see if an Esper statement already exists, and to skip the rule if it does? So far, I've tried catching the exception and simply returning a log stating that the EPL statement already exists, that way only new statements would be created:
private Exception e;
private void refreshStatement(Rule rule) throws Exception {
List<String> allRules = dao.getAllRules;
for (String rule : allRules) {
if (e instanceof ExprValidationException) {
log.info("The EPL statement already exists")
}
else {
EPStatement statement = epService.getEPAdministrator().createEPL(rule);
statement.addListener(new RuleListener(rule));
ruleMap.put(rule.getId(), statement);
}
}
}
However, I still got the same exception.
Edit: I just realized that I wrote the for loop wrong. The program will fail on when creating statement, and since that is in the else portion of the loop, it thus never checks for the exception.
You can get the currently-existing statements from EPAdministrator.getStatementNames() and EPAdministrator.getStatement(String name).
Comparing whether a statement already exists is up to your application but EPStatement.getText() returns you the EPL.
I have this project that I'm doing and for whatever reason, whenever I execute the program and put in the given arguments required for it (that I set and all) and occasionally an IOException is thrown before anything else is executed. It seems to be true because I got loggers everywhere and none of them are being fired. However, it seems that just the loggers are not being fired cause when I look in the json file I output to, it shows that it did do the first step of the execution, just no loggers. I'm new to log4j2 so it may be that but I'm not sure (with the loggers not being fired) but it seems weird that an IOException occurs when it shouldn't at all. Cause when I execute it again right after the crash, it runs just fine.
(Side note: this is in kotlin/jvm, but this is pertaining to the use of the JDK File class)
The exception is thrown here: https://github.com/AlexCouch/projauto/blob/master/src/main/java/thinkingcouch/projauto/Save.kt#L114
I'm on MacOSX High Sierra using Intellij IDEA 2017.3.
So what ended up happening was I had this function here for isolating a certain part of the given path to be appended to a new path and also saved to json for later use
fun Path.splitPathWithContext(context: String): File{
val presplit = this.normalize()
logger.info("presplit: $presplit")
logger.info("context: $context")
if(presplit.toString() == context){
logger.info("Path and context are the same.")
return presplit.toFile()
}
val reg = Pattern.compile("\\b$context\\b")
val ret = presplit.toString().split(reg)[1]
logger.info("ret: $ret")
return File(ret)
}
The solution was to do a strict pattern check against the context variable so that it doesn't cut at a word that contains that string but isn't that string exactly, and it needed to be exact. This solved my issue. No more problems, and no more broken paths, and I also fixed my loggers. I don't know exactly what was causing it to not do any logging, but I fixed it by setting the root level to "all" and then removing all my other logger elements since that's all I needed to do.
I have a cucumber scenario and the step uses assertEquals. My results report shows the stack trace which is not end user friendly. How can I suppress it
Scenario: Add two numbers
Given I have two inputs "3" and "2"
When I add them
Then the output should be "15"
You're correct in observing that the default XML output (assuming you're not outputting to JSON or text, but you didn't say) from a Junit tests show stack traces for failed steps. This isn't actually a Cucumber thing. CucumberOptions won't help you here.
You can:
Use a different or custom Runner for your test and then setup a tag that controls what is included in the output, or what will be read by the CI software of your choosing. For example the Confulence API API for doing this tells how "debugger"
Same type of deal for Ant Scripts to tweak the output, so that is doesn't show the output. A good Tutorial for learning how to use Any scripts to fire off your Cucumber JUnit Test is here.
Other have build a custom formatter for JUnit by implementing XMLJUnitResultFormatter API, explained more here - How do I configure JUnit Ant task to only produce output on failures?
Hope that gives you what you need.
I was also facing same issue with my Cucumber-Selenium-Java project. In the cucumber reports, it was generating around 40 lines of stacktrace. Due to this, it was impacting look and feel of the report. And the end user/client was little concerned about it. Because he/she was not really able to figure out the actual use of this stacktrace. So, I came up with below idea/approach. It's little bit tricky but, it's worthy.
Few notes before starting:
We cannot completely disable stacktrace in in all the cases. But we can modify the stacktrace and then, re-throw the new exception with useful and shortened stacktrace.
You need to be aware about frequently faced exceptions, errors. So that, we can create custom exception depending on the exceptions.
In the stacktrace it will generate few line of code from wrapper APIs, few lines from Junit/TestNg, few lines for java and selenium and there will be only one or two lines in the stacktrace, where actually our issue occurred.
Our test classes must be in unique package. So that, we can filter the stacktrace trace with package name and get the class name, line number and method name of actual issue and we can use this information in throwing custom exception. Hence, it will be easy to figure out the actual line of issue occurred. In my case all the classes were in package named "page". If you have more than one packages for your classes, then you can accordingly add string conditions in below code.
We need to wrap the test code in try-catch block. And while catching, we need to use Throwable class not exception class. Because, if there is any assertion failure, then Exception class won't be able to handle the issue as you know all the assertions come under Error class and Throwable is the parent of Error and Exception.
If we throw the new exception in catch block, then, it will change the line number in stacktrace, where actual issue occurred. So it will be difficult to figure out the actual line of issue. In order to avoid it, we need to get the class name, line number, method name of actual issue and store it in StackTraceElement class and use it in throwing new exception.
Some exceptions like "NoSuchElementException" provides lot of information in their cause and most of it is not really required, So we need to modify the content of it's message by using substring(), indexOf() and replaceAll() methods of String class in Java. And then, provide the modified information in new exception.
Few important Java method from Throwable java class and their description: (i) getStackTrace(): This method will return us array of StackTraceElement class. StackTraceElement class will provide us the class name, method name, line number at which issue is occurred. (ii) setStackTrace(): This method is used to provide a custom stacktrace to new Exception. (iii) getCause(): This method will provide the issue message from cause of exception. But sometimes, it might return null. Because for some exceptions "cause" might not be specified. So this needs be surround in try catch block and here we need to use getMessage() method for getting the actual error message. (iv) getClass(): This method will return the actual exception class name. We will use this method for figuring out the exception class name and then, we will use it for providing specific implementation for different different exception classes. Note: "getClass()" method is not from "Throwable" class. It is from Object class.
You need to create a common method for handling all the exceptions and reuse this method in all the required classes. e.g.: I have named the method as "processException" and placed it in "ReusableMethod" class.
Note that, I am using package name "page" in below method (line#8), because all my test classes are placed in this package. In your case you need to update the package name as per your need. Also, I have written custom cases for two exceptions only: NoSuchElementException & AssertionError. You might need to write more cases as per your need.
public void processException(Throwable e) throws Exception {
StackTraceElement[] arr = e.getStackTrace();
String className = "";
String methodName = "";
int lineNumber = 0;
for (int i = 0; i < arr.length; i++) {
String localClassName = arr[i].getClassName();
if (localClassName.startsWith("page")) {
className = localClassName;
methodName = arr[i].getMethodName();
lineNumber = arr[i].getLineNumber();
break;
}
}
String cause = "";
try {
cause = e.getCause().toString();
} catch (NullPointerException e1) {
cause = e.getMessage();
}
StackTraceElement st = new StackTraceElement(className, methodName, "Line", lineNumber);
StackTraceElement[] sArr = { st };
if (e.getClass().getName().contains("NoSuchElementException")) {
String processedCause = cause.substring(cause.indexOf("Unable to locate"), cause.indexOf("(Session info: "))
.replaceAll("\\n", "");
Exception ex = new Exception("org.openqa.selenium.NoSuchElementException: " + processedCause);
ex.setStackTrace(sArr);
throw ex;
} else if (e.getClass().getName().contains("AssertionError")) {
AssertionError ae = new AssertionError(cause);
ae.setStackTrace(sArr);
throw ae;
} else {
Exception ex = new Exception(e.getClass() + ": " + cause);
ex.setStackTrace(sArr);
throw ex;
}
}
Below is the sample Method to showcase the usages of above method in Test Class methods. We are calling the above created method by using the class reference, which is "reuseMethod" in my case. And we are passing the caught Throwable reference "e" to the above method in catch block:
public void user_Navigates_To_Home_Page() throws Exception {
try {
//Certain lines of code as per your tests
//element.click();
} catch (Throwable e) {
reuseMethod.processException(e);
}
}
Here are few screenshots for implementation of NoSuchElementException:
Before Implementing this approach:
After Implementing this approach:
EDIT2
#paradigmatic made a good point in suggesting to redirect rather than throw the exception; that solves the logging issue. The problem in Play 2 is that redirects need to occur within so-called Action scope, which is not always the case with date parser calls.
As a workaround, I went with Play's global interceptor, presumably the equivalent of a Java servlet filter.
val ymdMatcher = "\\d{8}".r // matcher for yyyyMMdd URI param
val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
def ymd2Date(ymd: String) = ymdFormat.parseDateTime(ymd)
override def onRouteRequest(r: RequestHeader): Option[Handler] = {
import play.api.i18n.Messages
ymdMatcher.findFirstIn(r.uri) map{ ymd=>
try { ymd2Date( ymd); super.onRouteRequest(r) }
catch { case e:Exception => // kick to "bad" action handler on invalid date
Some(controllers.Application.bad(Messages("bad.date.format")))
}
} getOrElse(super.onRouteRequest(r))
}
EDIT
Here 's a little context to work with:
// String "pimp": transforms ymdString.to_date call into JodaTime instance
class String2Date(ymd: String) {
def to_date = {
import play.api.i18n.Messages
try{ ymdFormat.parseDateTime(ymd) }
catch { case e:Exception => throw new NoTrace(Messages("bad.date.format")) }
}
val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
}
#inline implicit final def string2Date(ymd: String) = new String2Date(ymd)
and a test custom exception handler:
public class NoTrace extends Exception {
static final long serialVersionUID = -3387516993124229948L;
#Override
public Throwable fillInStackTrace() {
return null;
}
public NoTrace(String message) {
super(message);
}
}
Calling the date parser on an invalid yyyyMMdd string logs 30 line stack trace to the log (this occurs upstream by Play framework/Netty container, better than default 100 line trace):
"20120099".to_date
ORIGINAL
Have an issue where my application.log is getting filled with errors related to a uri date parser operation that should succeed given a valid yyyyMMdd uri date.
However, some users try to circumvent this by entering invalid dates in hopes of gaining free access to paid subscriber-only content. It's pointless, as it simply won't work, but regardless, I have MBs of these error traces in my application log.
Is there a way to throw a truly trimmed down Exception to the log? I found this SO answer, but in my application it looks like the container (Play framework on Netty) gets into the mix and logs its own 30 line stack trace to the log (30 lines is better than 100, but still 29 too many)
Similarly, I found this thread in regard to Java 7 and the new option to suppress stack trace; however, for some reason, despite being on Java 1.7, with Eclipse configured for Java 1.7, only the old 2 param method of Throwable is available (and I do see the 4 param method when I click through to the Throwable class; maybe a Scala 2.9.2 library issue?)
At any rate, ideally I can simply log a 1-line exception message and not the kitchen sink.
Simply override this method in your custom exception class:
#Override
public Throwable fillInStackTrace() {
return this;
}
after adding this method your trace method will not print
Your trouble is that although you can suppress the stacktrace of the exception your own code threw, there is nothing you can do about the exception it will be wrapped into by the framework. The only avenue I can see is not allowing the framework to catch your exception at all (doing your own top-level handling) or tweaking the logging configuration.
I think you have two options:
Control the logging to not save stack traces for some exceptions.
Write a post-processor that filters out the traces from the log file.
Unless you are in danger of running out of disk space, I think #2 is the better option, because if you do have a bug you can go back to the full log and have all the exception history.
The philosophy behind idea #2 is that disk space is cheap, but information can be precious during debug. Log a lot of data. Normally, use scripts to examine the log after it has been written to disk.
For example, if there is a type of log entry that you never expect to see, but that demands immediate action if it does appear, write a script that searches for it, and send you an e-mail if it finds one.
One of the most useful forms of script in this approach is one that drops stack trace lines. Usually, you only need to know what exceptions are happening, and the stack trace takes up a lot of screen space without telling you much. If you do need to investigate an exception, go back to the full log, find the exception line, and look at the stack trace and at what was happening immediately before the exception.
If there are too many of your date exceptions, have the script drop even the exception line. If you want to track how often they are happening, run a script that counts date exceptions per hour.
That sort of script typically costs a few minutes of programming in your favorite regex-capable script language.