Auditing Rules
Track which rules fired, skipped, stopped, or failed - or preview it with dryRun().
Auditing Rules
Rule auditing tells you which rules fired and which didn't. A RuleBook
tracks this in a RuleStatusMap. Give your rules a name so the audit
trail is meaningful - otherwise you'll see the rule's internal UUID
instead. You can name a rule in any of these ways:
// Using the Builder
builder.rule( "ruleName" )
// Using newRule()
addRule( newRule( "ruleName" ) )
// Or its setter
addRule( newRule().setName( "ruleName" ) )
Rule states
Each rule added to a RuleBook has its state tracked via
RULE_STATES, exposed on every RuleBook instance:
| State | Meaning |
|---|---|
REGISTERED | The rule has been added to the RuleBook, not yet evaluated this run |
EXECUTED | The rule's when() (and except()) passed and its then() action(s) completed successfully |
SKIPPED | The rule's when()/except() condition did not pass |
STOPPED | The rule executed and then called stop(), halting the chain |
FAILED | A then() consumer threw - see Error Handling |
NOT_AVAILABLE | Returned by getRuleStatus() for a name that isn't in the map |
RuleBook.run() resets every registered rule's status back to
REGISTERED at the start of each run, so a rule that a shorter chain
doesn't reach this time around never reports a stale status left over
from a previous run.
Reading the audit trail
status = ruleBook.getRuleStatus( "rule1" )
status = ruleBook.getRuleStatus( "rule2" )
Or retrieve the entire map:
writeDump( ruleBook.getRuleStatusMap() )
Dry-run / explain mode
Sometimes you want to know which rules a given set of facts would
trigger, without actually triggering them - no then() consumers run, no
facts are merged into the sticky fact store, no Result is touched, and
the real audit trail (getRuleStatusMap()) is left exactly as it was.
dryRun() gives you that preview, on both RuleBook and Rule:
report = ruleBook.dryRun( { "creditScore" : 550 } )
writeDump( report )
RuleBook.dryRun() returns an array of structs, one per rule reached, in
execution order:
[
{ "name" : "checkBlocklist", "wouldExecute" : false, "wouldStop" : false },
{ "name" : "creditScoreAdjustment", "wouldExecute" : true, "wouldStop" : false }
]
The walk stops exactly where a real run() would stop - the first rule
whose condition passes and has stop() set. Rules after that point are
never reached, so (just like a real run) they simply don't appear in the
report.
A single Rule can also be dry-run on its own - and unlike run(), it
doesn't require being attached to a RuleBook first:
report = newRule()
.when( ( facts ) => facts.creditScore < 600 )
.stop()
.dryRun( { "creditScore" : 550 } )
// { "name" : "...", "wouldExecute" : true, "wouldStop" : true }