krill: simple boolean filter language
Krill provides functions for validating and evaluating boolean filters (also
called predicates) expressed in a simple JSON language that's intended to be
easy to incorporate into JSON APIs.
Synopsis
The basic idea is that you construct a predicate as a boolean expression that
uses variables (called fields). You can then evaluate the predicate with a
particular assignment of variables.
You can specify types for each field, in which case the expression itself will
be type-checked when you create it.
var types = {
'hostname': 'string',
'latency': 'number'
};
var input = {
'or': [
{ 'eq': [ 'hostname', 'spike' ] },
{ 'gt': [ 'latency', 300 ] }
]
};
console.log(input);
var predicate = krill.createPredicate(input, types);
A trivial predicate is one that's just "true":
console.log('trivial? ', predicate.trivial());
You can print out the fields (variables) used in this predicate:
console.log('fields: ', predicate.fields().join(', '));
You can also print a C-syntax expression for this predicate, which you can
actually plug directly into a C-like language (like JavaScript) to evaluate it:
console.log('DTrace format: ', predicate.toCStyleString());
You can also evaluate the predicate for a specific set of values:
var value = { 'hostname': 'spike', 'latency': 12 };
console.log(value, predicate.eval(value));
value = { 'hostname': 'sharptooth', 'latency': 400 };
console.log(value, predicate.eval(value));
value = { 'hostname': 'sharptooth', 'latency': 12 };
console.log(value, predicate.eval(value));
JSON input format
All predicates can be represented as JSON objects, and you typically pass such
an object into createPredicate
to work with them. The simplest predicate is:
{}
The general pattern for relational operators is:
{ 'OPERATOR': [ 'VARNAME', 'VALUE' ] }
In all of these cases, OPERATOR must be one of the built-in operators, VARNAME
can be any string, and VALUE should be either a specific string or numeric
value.
The built-in operators are:
'eq'
: is-equal-to (strings and numbers)'ne'
: is-not-equal-to (strings and numbers)'lt'
: is-less-than (numbers only)'le'
: is-less-than-or-equal-to (numbers only)'ge'
: is-greater-than-or-equal-to (numbers only)'gt'
: is-greater-than (numbers only)
For examples:
{ 'eq': [ 'hostname', 'spike' ] }
{ 'lt': [ 'count', 15 ] }
You can also use "and" and "or", which have the form:
{ 'or': [ expr1, expr2, ... ] }
{ 'and': [ expr1, expr2, ... ] }
where expr1
, expr2
, and so on are any other predicate. For example:
{
'or': [
{ 'eq': [ 'hostname', 'spike' ] },
{ 'gt': [ 'latency', 300 ] }
]
};
is logically equivalent to the C expression:
hostname == "spike" || latency > 300