I\'ve one .DRL file which has say 10 rules. Once I insert a fact, some rules may be matched- how do I find out which rules were matched programmatically?
Note that this answer is valid for versions of Drools up to 5.x. If you have moved on to 6 or above, then take a look at the modified answer from @melchoir55. I haven't tested it myself, but I'll trust that it works.
To keep track of rule activations, you can use an AgendaEventListener. Below is an example, as found here:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/drools/util/TrackingAgendaEventListener.java
You just need to create such a listener and attach it to the session like so:
ksession = kbase.newStatefulKnowledgeSession();
AgendaEventListener agendaEventListener = new TrackingAgendaEventListener();
ksession.addEventListener(agendaEventListener);
//...
ksession.fireAllRules();
//...
List<Activation> activations = agendaEventListener.getActivationList();
Note that there is also WorkingMemoryEventListener which enables you to do the same with tracking insertions, updates and retractions of facts.
Code for a tracking & logging AgendaEventListener:
package com.sctrcd.drools.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.drools.definition.rule.Rule;
import org.drools.event.rule.DefaultAgendaEventListener;
import org.drools.event.rule.AfterActivationFiredEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A listener that will track all rule firings in a session.
*
* @author Stephen Masters
*/
public class TrackingAgendaEventListener extends DefaultAgendaEventListener {
private static Logger log = LoggerFactory.getLogger(TrackingAgendaEventListener.class);
private List<Activation> activationList = new ArrayList<Activation>();
@Override
public void afterActivationFired(AfterActivationFiredEvent event) {
Rule rule = event.getActivation().getRule();
String ruleName = rule.getName();
Map<String, Object> ruleMetaDataMap = rule.getMetaData();
activationList.add(new Activation(ruleName));
StringBuilder sb = new StringBuilder("Rule fired: " + ruleName);
if (ruleMetaDataMap.size() > 0) {
sb.append("\n With [" + ruleMetaDataMap.size() + "] meta-data:");
for (String key : ruleMetaDataMap.keySet()) {
sb.append("\n key=" + key + ", value="
+ ruleMetaDataMap.get(key));
}
}
log.debug(sb.toString());
}
public boolean isRuleFired(String ruleName) {
for (Activation a : activationList) {
if (a.getRuleName().equals(ruleName)) {
return true;
}
}
return false;
}
public void reset() {
activationList.clear();
}
public final List<Activation> getActivationList() {
return activationList;
}
public String activationsToString() {
if (activationList.size() == 0) {
return "No activations occurred.";
} else {
StringBuilder sb = new StringBuilder("Activations: ");
for (Activation activation : activationList) {
sb.append("\n rule: ").append(activation.getRuleName());
}
return sb.toString();
}
}
}
Change the dialect to JAVA in DRL file.
Insert a HashMap from the java file to DRL file (using Drools session concept), which should contain the rule name as key and boolean value as result.
Follow this link to know how to insert Map to the DRL file.
You can now find which rule exactly matched.
Hope this helps :)
You can print info about rule executed from DRL file itself using RuleContext:drools
System.out.println(drools.getRule().getName())
Steve's answer is solid, but the major changes brought in drools 6 make the code obsolete. I am posting below a rewrite of Steve's code which takes into account the new api:
package your.preferred.package;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.drools.core.event.DefaultAgendaEventListener;
import org.kie.api.definition.rule.Rule;
import org.kie.api.event.rule.AfterMatchFiredEvent;
import org.kie.api.runtime.rule.Match;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A listener that will track all rule firings in a session.
*
* @author Stephen Masters, Isaac Martin
*/
public class TrackingAgendaEventListener extends DefaultAgendaEventListener {
private static Logger log = LoggerFactory.getLogger(TrackingAgendaEventListener.class);
private List<Match> matchList = new ArrayList<Match>();
@Override
public void afterMatchFired(AfterMatchFiredEvent event) {
Rule rule = event.getMatch().getRule();
String ruleName = rule.getName();
Map<String, Object> ruleMetaDataMap = rule.getMetaData();
matchList.add(event.getMatch());
StringBuilder sb = new StringBuilder("Rule fired: " + ruleName);
if (ruleMetaDataMap.size() > 0) {
sb.append("\n With [" + ruleMetaDataMap.size() + "] meta-data:");
for (String key : ruleMetaDataMap.keySet()) {
sb.append("\n key=" + key + ", value="
+ ruleMetaDataMap.get(key));
}
}
log.debug(sb.toString());
}
public boolean isRuleFired(String ruleName) {
for (Match a : matchList) {
if (a.getRule().getName().equals(ruleName)) {
return true;
}
}
return false;
}
public void reset() {
matchList.clear();
}
public final List<Match> getMatchList() {
return matchList;
}
public String matchsToString() {
if (matchList.size() == 0) {
return "No matchs occurred.";
} else {
StringBuilder sb = new StringBuilder("Matchs: ");
for (Match match : matchList) {
sb.append("\n rule: ").append(match.getRule().getName());
}
return sb.toString();
}
}
}
You can use a static logger factory which will log with your favorite logger the actions from your DRL file.
For instance:
import org.drools.runtime.rule.RuleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class DRLLogger {
private DRLLogger() {
}
protected static Logger getLogger(final RuleContext drools) {
final String category = drools.getRule().getPackageName() + "." + drools.getRule().getName();
final Logger logger = LoggerFactory.getLogger(category);
return logger;
}
public static void info(final RuleContext drools, final String message, final Object... parameters) {
final Logger logger = getLogger(drools);
logger.info(message, parameters);
}
public static void debug(final RuleContext drools, final String message, final Object... parameters) {
final Logger logger = getLogger(drools);
logger.debug(message, parameters);
}
public static void error(final RuleContext drools, final String message, final Object... parameters) {
final Logger logger = getLogger(drools);
logger.error(message, parameters);
}
}
Then from your DRL file:
import function com.mycompany.DRLLogger.*
rule "myrule"
when
$fact: Fact()
then
info(drools, "Fact:{}", $fact);
end