Rules
Rules are defined under a rules
object. The terms
map allows common expressions to be reused in one or more rules to improve readability and avoid repeating expressions. The terms
map is optional.
Field | Required? | Description |
---|---|---|
rules | Yes | The list of rule definitions. Each rule embeds one or more rule . |
terms | No | A map of named expressions that may be reused in one or more rules. Conditions may be referenced by name in rules as needed. Term names are globally reusable/unique. |
Rule
A rule
describes a network of conditions that must be true across one or more abstract data source
. A rule is either a collection or an ordered list of conditions. Collections are called a set
and ordered lists are called a sequence
.
One or more nested conditions from another sequence
or set
may be used as as a condition of another set
or sequence
. Nested expressions enable complex positive and negative conditions to be created across distributed data sources.
Conditions are literal strings, jq
queries (for structured data), or regular expressions.
Field | Required? | Description |
---|---|---|
sequence | Yes | An ordered collection of two or more positive conditions and/or zero or more negative conditions where order matters and repetitions (duplicates) are allowed, e.g. A followed by B followed by and C. Positive conditions must be described in an order object. |
set | Yes | A collection of one or more distinct positive and/or negative conditions forming a group, e.g. A, B, and C in any order with no duplicates. Positive conditions must be described in a match object. |
Rules Document
rules:
- cre:
id: cre-2025-0
metadata:
id: rule-id-0
hash: rule-hash-0
rule:
set:
window: 5s
event:
source: kafka
match:
- commonExpression1
- "this is another match"
- cre:
id: cre-2025-1
metadata:
id: rule-id-1
hash: rule-hash-1
rule:
sequence:
window: 10s
event:
source: kafka
order:
- regex: "foo(.+)bar"
- commonExpression1
- commonExpression2
# Optional terms section for reusing common conditions
terms:
commonExpression1:
regex: "bo(.+)r"
commonExpression2:
value: "some other match"
Add the rule document on the command line or in the configuration file to use the new rules.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:38 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to baaz
2019/02/05 12:07:41 [emerg] 1655#1655: bind() foo bar
2019/02/05 12:07:42 [emerg] 1655#1655: bind() boooor
2019/02/05 12:07:43 [emerg] 1655#1655: bind() some other match
2019/02/05 12:07:44 [emerg] 1655#1655: bind() this is another match
2019/02/05 12:07:45 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:46 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:47 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:48 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat examples/00-example.log | preq -r ./examples/00-rules-document-example.yaml -d
Example output
Parsing rules done! [2 rules in 1ms; 2.47K rules/s]
Problems detected done! [2 in 1ms; 2.43K/s]
Matching lines done! [12 lines in 1ms; 14.42K lines/s]
Reading stdin done! [906B in 0s; 2.91MB/s]
cre-2025-0 critical [1 hits @ 2019-02-05T06:07:37-06:00]
cre-2025-1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Wrote report to preq-report-1743512495.json
[
{
"cre": {
"id": "cre-2025-1"
},
"hits": [
{
"timestamp": "2019-02-05T06:07:41-06:00",
"entry": "2019/02/05 12:07:41 [emerg] 1655#1655: bind() foo bar"
},
{
"timestamp": "2019-02-05T06:07:42-06:00",
"entry": "2019/02/05 12:07:42 [emerg] 1655#1655: bind() boooor"
},
{
"timestamp": "2019-02-05T06:07:43-06:00",
"entry": "2019/02/05 12:07:43 [emerg] 1655#1655: bind() some other match"
}
],
"id": "cre-2025-1",
"rule_hash": "rule-hash-1",
"rule_id": "rule-id-0",
"timestamp": "2019-02-05T06:07:41-06:00"
},
{
"cre": {
"id": "cre-2025-0"
},
"hits": [
{
"timestamp": "2019-02-05T06:07:42-06:00",
"entry": "2019/02/05 12:07:42 [emerg] 1655#1655: bind() boooor"
},
{
"timestamp": "2019-02-05T06:07:44-06:00",
"entry": "2019/02/05 12:07:44 [emerg] 1655#1655: bind() this is another match"
}
],
"id": "cre-2025-0",
"rule_hash": "rule-hash-0",
"rule_id": "rule-id=0",
"timestamp": "2019-02-05T06:07:42-06:00"
}
]
The -d
option disables community CREs while testing a new rule to contribute to the problem detection community. See Getting Started for more information.
Try out this example in the playground!
Set
A set
is a collection of one or more distinct (unique) positive and (optionally) negative conditions that form a group of matches that can occur in any order. Duplicate conditions—conditions that match the exact same thing—are not allowed in a set
. Conditions in a set
must be unique.
Positive conditions must be described in a match
object. Negative conditions use a negate
object.
One positive condition
Use match
to define conditions in a set
. A set
is used for rules that have only one positive condition.
rules:
- cre:
id: set-example
rule:
set:
event:
source: kafka
match:
- "foo(.+)bar"
This set
rule will match the following data.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 01-example.yaml | preq -r ./01-set-single-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.26K rules/s]
Problems detected done! [1 in 0s; 2.15K/s]
Reading stdin done! [822B in 0s; 3.10MB/s]
Matching lines done! [10 lines in 0s; 36.23K lines/s]
set-example critical [1 hits @ 2019-02-05T06:07:38-06:00]
Multiple positive conditions
More than one positive condition can be used in a set
.
rules:
- cre:
id: set-example-2
rule:
set:
window: 10s
event:
source: kafka
match:
- value: "test"
- regex: "foo(.+)bar"
- regex: "b(.+)az"
This set
rule will match the following data.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 02-example.log | preq -r ./02-set-multiple-example-good-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.41K rules/s]
Problems detected done! [1 in 0s; 2.33K/s]
Reading stdin done! [822B in 0s; 4.11MB/s]
Matching lines done! [10 lines in 0s; 50.00K lines/s]
set-example-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
The same rule will also match this data even though the conditions are in a different order:
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 02-example-1.log | preq -r ./02-set-multiple-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.41K rules/s]
Problems detected done! [1 in 0s; 2.33K/s]
Reading stdin done! [822B in 0s; 4.11MB/s]
Matching lines done! [10 lines in 0s; 50.00K lines/s]
set-example-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Match window
Two or more positive conditions require a match window
. A match window
describes the maximum amount of time that is allowed to pass between matches of the first and last positive conditions. If one or more conditions matches outside the window, the rule will not fire.
rules:
- cre:
id: set-example-2
rule:
set:
window: 1s
event:
source: kafka
match:
- value: "test"
- regex: "foo(.+)bar"
- regex: "b(.+)az"
This set
rule will not match the same data as above because the third positive condition occurs outside the rule's new 1s window.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 02-example-1.log | preq -r ./02-set-multiple-example-bad-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.41K rules/s]
Problems detected done! [1 in 0s; 2.33K/s]
Reading stdin done! [822B in 0s; 4.11MB/s]
Matching lines done! [10 lines in 0s; 50.00K lines/s]
Negative conditions
A set
may use one or more negative condition to reduce false positive detections (FPs).
rules:
- cre:
id: set-negative
rule:
set:
window: 10s
event:
source: kafka
match:
- value: "test"
- regex: "foo(.+)bar"
- regex: "b(.+)az"
negate:
- already in use
This set
rule will not match the following data because of the negative condition highlighted below.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:38 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 03-example.log | preq -r ./03-set-negative-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.01K rules/s]
Problems detected done! [0 in 1ms; 0/s]
Reading stdin done! [725B in 0s; 4.01MB/s]
Matching lines done! [9 lines in 0s; 49.72K lines/s]
By default, negative conditions cannot occur between the first and last positive condition. But this behavior can be modified with negate options.
One positive and one negative condition may be used in a set
. However, without additional negate options, the negative condition must occur at the exact same time to fire.
rules:
- cre:
id: set-1x1
rule:
set:
window: 10s
event:
source: kafka
match:
- value: "test"
negate:
- already in use
This set
rule will not match the following data because of the negative condition occurs at the same time as the positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 04-example.log | preq -r ./04-set-1x1-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.32K rules/s]
Problems detected done! [0 in 1ms; 0/s]
Reading stdin done! [822B in 0s; 5.11MB/s]
Matching lines done! [10 lines in 0s; 60.98K lines/s]
If the negative condition occurs at a different time, the rule will fire.
Common pitfalls
An order
is not allowed in a set
Use match
instead. The order
term is reserved for describing positive conditions in a sequence
.
rules:
- cre:
id: bad-order
rule:
set:
event:
source: kafka
order: # Use match instead
- bar
$ cat *.log | preq -r 05-bad-set-example.yaml -d -N
Rules error: set missing match
One negative not allowed
A single negative condition alone is not allowed in either a set
or a sequence
.
rules:
- cre:
id: bad-negate
rule:
set:
event:
source: kafka
negate: # Negates may not be used without positive conditions
- "foo(.+)bar"
$ cat *.log | preq -r 06-bad-set-example.yaml -d -N
Rules error: missing one or more positive condition under a match statement
Two positive terms without a window
not allowed
A window
is required for more than one positive term.
rules:
- cre:
id: bad-window
rule:
set:
# missing window
event:
source: kafka
match:
- foo
- bar
$ cat *.log | preq -r 07-bad-set-window.yaml -d -N
Rules error: invalid window
Sequence
A sequence
defines two or more positive conditions that must occur in the same order as defined in the order
object. A sequence
with only one positive condition is not allowed. Use a set
instead for a single positive condition.
A single negative condition is not allowed without two or more positive conditions in a sequence
.
Multiple positive conditions
rules:
- cre:
id: seq-example-1
rule:
sequence:
event:
source: kafka
window: 10s
order:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
This rule matches the following data:
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 08-example.log | preq -r 08-sequence-example-good-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.08K rules/s]
Problems detected done! [1 in 1ms; 1.06K/s]
Reading stdin done! [736B in 0s; 1.09MB/s]
Matching lines done! [9 lines in 0s; 13.16K lines/s]
seq-example-1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Order window
Two or more positive conditions in a sequence
require an order window
. An order window
describes the maximum amount of time that is allowed to pass between matches of the first and last positive conditions. If one or more conditions match outside the window, the rule will not fire.
rules:
- cre:
id: seq-example-1
rule:
sequence:
event:
source: kafka
window: 1s
order:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
This rule does not match the following data because the third positive conditions occurs outside the rule's new 1s window:
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 08-example.log | preq -r 08-sequence-example-good-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.08K rules/s]
Problems detected done! [1 in 1ms; 1.06K/s]
Reading stdin done! [736B in 0s; 1.09MB/s]
Matching lines done! [9 lines in 0s; 13.16K lines/s]
seq-example-1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Negative conditions
- rule:
sequence:
event:
source: kafka
window: 10s
order:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- already in use
This rule will not fire on the following data because of the highlighted negative conditions that occurs after the first and before the last positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 09-example.log | ../bin/preq-linux-amd64 -r 09-sequence-negate-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.19K rules/s]
Problems detected done! [0 in 1ms; 0/s]
Reading stdin done! [736B in 0s; 5.41MB/s]
Matching lines done! [9 lines in 0s; 66.67K lines/s]
Common pitfalls
match
conditions not allowed
A match
cannot be used with a sequence
. Use order
instead.
rules:
- cre:
id: bad-seq-match
rule:
sequence:
event:
source: kafka
window: 10s
match: # use order instead
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
$ cat *.log | preq -r ./10-bad-sequence-match-example.yaml -d -N
Rules error: sequence missing order
One positive condition not allowed
A sequence
with only one condition is not supported.
rules:
- cre:
id: bad-seq-one-condition
rule:
sequence:
event:
source: kafka
order:
- regex: "foo(.+)bar" # one condition not allowed
$ cat *.log | preq -r ./11-bad-sequence-one-condition.yaml -d -N
Rules error: sequences require two or more positive conditions
One negative condition not allowed
A negative condition by itself is not allowed. It always requires relative positive conditions.
rules:
- cre:
id: bad-seq-one-negate-condition
rule:
sequence:
event:
source: kafka
negate:
- regex: "foo(.+)bar" # one negate condition not allowed
$ cat *.log | preq -r ./12-bad-sequence-one-negate.yaml -d -N
Rules error: sequences require two or more positive conditions
Conditions
Conditions describe how to match patterns that exist in any data source with a timestamp. Positive (or "matching") and negative (or "inverse" or "absent") conditions on data sources can be expressed in one of three ways:
Field | Type | Description |
---|---|---|
value | string | A UTF-8 encoded string that supports unicode characters. |
regex | string | RE2-style regular expressions |
jq | string | A jq formatted query string |
String Values
Strings can be added in quotes using the value
field to match this string in the example data below.
rules:
- cre:
id: string-example-1
rule:
set:
event:
source: kafka
match:
- value: "[emerg] 1655#1655: still could not bind()"
This will match the highlighted line below.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind()
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 13-example.log | preq -r ./13-string-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.15K rules/s]
Problems detected done! [1 in 1ms; 1.13K/s]
Reading stdin done! [807B in 0s; 3.62MB/s]
string-example-1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [9 lines in 0s; 40.18K lines/s]
String values may also be expressed without the value
field.
rules:
- cre:
id: string-example-2
rule:
set:
event:
source: kafka
match:
- "[emerg] 1655#1655: still could not bind()"
cat 14-example.log | preq -r ./14-string-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.70K rules/s]
Problems detected done! [1 in 0s; 1.64K/s]
Reading stdin done! [807B in 0s; 2.97MB/s]
string-example-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [9 lines in 0s; 32.03K lines/s]
Escape Sequences
Use a backslash \
to escape the following special characters in a string value:
\r
carriage return CR\n
new line LF\t
tab\'
single quotes '\"
double quotes "\\
backslash \\u
for 4-digit hexadecimal code points (e.g., \u00E9 for é)\U
for 8-digit hexadecimal code points (e.g., \U0001F600 for 😀)
Regular Expressions
Regular expressions can be added in quotes using the regex
field. Regular expressions ignore parts of a condition that may change frequently, like the 1655#1655
process and thread IDs in the example.
rules:
- cre:
id: regex-example-1
rule:
set:
event:
source: kafka
match:
- regex: "emerg(.+)still could not bind()"
This regular expression will match the highlighted line below.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind()
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 15-example.log | preq -r ./15-regex-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.89K rules/s]
Problems detected done! [1 in 0s; 2.78K/s]
Reading stdin done! [807B in 0s; 5.24MB/s]
regex-example-1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [9 lines in 0s; 55.90K lines/s]
The following regular expression special characters must be escaped using a backslash \
:
\.+*?()|[]{}^$`
An escape backslash \
must also be escaped in the Yaml string. This means two backslashes are needed. One for the Yaml string and the other for the regular expression.
rules:
- cre:
id: regex-example-2
rule:
set:
event:
source: kafka
match:
- regex: "\\[emerg] (.+) still could not bind()"
This will match the highlighted line below.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:443 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: still could not bind()
2019/02/05 12:07:41 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 16-example.log | preq -r ./16-regex-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.10K rules/s]
Problems detected done! [1 in 1ms; 1.08K/s]
Reading stdin done! [807B in 0s; 3.77MB/s]
Matching lines done! [9 lines in 0s; 43.69K lines/s]
regex-example-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
jq
Expressions
jq
expressions may be used on structured JSON or Yaml data sources.
rules:
- cre:
id: jq-example-1
rule:
set:
event:
source: kafka
match:
- jq: ".event == \"worker_process_crash\""
This jq
expression will match the highlighted line below.
{"timestamp":"2025-03-26T14:01:02Z","level":"info","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","request_id":"req001","method":"GET","path":"/","status":200,"latency_ms":5,"upstream":"web-service:80","client_ip":"192.168.1.10"}
{"timestamp":"2025-03-26T14:01:03Z","level":"info","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","request_id":"req002","method":"GET","path":"/api/status","status":200,"latency_ms":12,"upstream":"api-service:8080","client_ip":"192.168.1.11"}
{"timestamp":"2025-03-26T14:01:04Z","level":"error","event":"worker_process_crash","message":"worker process 4123 exited on signal 9","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","worker_pid":4123,"exit_signal":9}
{"timestamp":"2025-03-26T14:01:10Z","level":"warn","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","request_id":"req003","method":"POST","path":"/api/login","status":401,"latency_ms":15,"upstream":"auth-service:9000","client_ip":"192.168.1.12"}
{"timestamp":"2025-03-26T14:01:11Z","level":"info","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","request_id":"req004","method":"GET","path":"/metrics","status":200,"latency_ms":1,"upstream":"metrics-service:9090","client_ip":"192.168.1.15"}
{"timestamp":"2025-03-26T14:01:12Z","level":"info","service":"nginx-ingress","namespace":"default","pod":"nginx-ingress-abc123","request_id":"req005","method":"GET","path":"/healthz","status":200,"latency_ms":1,"upstream":"health-service:8081","client_ip":"192.168.1.18"}
cat 17-example.log | preq -r 17-jq-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 973 rules/s]
Problems detected done! [1 in 1ms; 990/s]
Reading stdin done! [1.60KB in 0s; 7.23MB/s]
jq-example-1 critical [1 hits @ 2025-03-26T09:01:04-05:00]
Matching lines done! [6 lines in 0s; 26.67K lines/s]
Use more complex jq
queries to match on more than one field in the data.
rules:
- cre:
id: jq-example-2
rule:
set:
event:
source: kafka
match:
- jq: "select(.event == \"worker_process_crash\" and .level == \"error\")"
cat 18-example.log | preq -r ./18-jq-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 850 rules/s]
Problems detected done! [1 in 1ms; 885/s]
Reading stdin done! [1.60KB in 0s; 7.23MB/s]
jq-example-2 critical [1 hits @ 2025-03-26T09:01:04-05:00]
Matching lines done! [6 lines in 0s; 26.09K lines/s]
Common pitfalls
Avoid Yaml literal-block scalers |
Avoid using Yaml literal-block scalars (e.g. |
) in conditions. The literal-block scalar adds a line feed \n
at the end of the string.
rules:
- cre:
id: bad-yaml-literal-block
rule:
set:
event:
source: kafka
match:
- regex: |
"\\[emerg] (.+) still could not bind()"
This will add a \n
to the end of the expression. As a result, it will no longer match the example data.
$ cat *.log | preq -r 19-bad-literal-block-example.yaml -d -N
Parsing rules done! [1 rules in 0s; 1.88K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [11.95KB in 0s; 47.22MB/s]
Matching lines done! [105 lines in 0s; 420.00K lines/s]
A regular expression may not be used without using the regex
field.
rules:
- cre:
id: bad-regex-example
rule:
set:
event:
source: kafka
match:
- "\\[emerg] (.+) still could not bind()" # use regex: instead
Negative conditions
Negative conditions are used to reduce false positives in a set
or sequence
. By default, a negative condition cannot occur between the first and last positive condition in a match
or an order
.
Simple negative condition
- rule:
sequence:
event:
source: kafka
window: 10s
order:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- this is normal
This sequence
rule would not match the following data because of the negative condition that occurs between the first and last positive condition in the sequence
.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 21-example.log | preq -r ./21-negative-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 948 rules/s]
Problems detected done! [0 in 1ms; 0/s]
Reading stdin done! [822B in 0s; 3.01MB/s]
Matching lines done! [10 lines in 0s; 34.97K lines/s]
The same sequence
rule would match the following data because the negative condition happens after the last positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:45 [emerg] 1655#1655: bind() just kidding false alarm this is normal
cat 22-example.log | preq -r ./21-negative-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.27K rules/s]
Problems detected done! [1 in 1ms; 1.20K/s]
Reading stdin done! [822B in 0s; 1.24MB/s]
Matching lines done! [10 lines in 0s; 14.99K lines/s]
negate-example critical [1 hits @ 2019-02-05T06:07:38-06:00]
It would also match this data because the negative condition happens before the first positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:43 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:44 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 23-example.log | preq -r ./21-negative-example.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.22K rules/s]
Problems detected done! [1 in 1ms; 1.20K/s]
Reading stdin done! [822B in 0s; 5.04MB/s]
negate-example critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [10 lines in 0s; 61.35K lines/s]
To match the last two examples add negate options to the negative conditions.
Multiple negative conditions
More than one negative condition may be used.
rules:
- cre:
id: multiple-negatives
rule:
sequence:
event:
source: kafka
window: 10s
order:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- FP1
- FP2
- FP3
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:40 [emerg] FP1
2019/02/05 12:07:40 [emerg] FP2
2019/02/05 12:07:41 [emerg] FP3
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 24-example.log | preq -r ./24-multiple-negatives.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.80K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [918B in 0s; 1.78MB/s]
Matching lines done! [13 lines in 0s; 24.81K lines/s]
Negate options
Negative conditions provide additional options to match (or reset) the rule. This is helpful in chaotic distributed systems where additional windows of time is needed before, during, or after positive conditions to prevent a rule from firing on a false positive (FP).
Window
The negate window
is used to extend or move the amount of time in which a negative condition cannot occur relative to the positive conditions.
The following set
rule defines one positive and one negative condition.
rules:
- cre:
id: negate-options-1x1
rule:
set:
event:
source: kafka
match:
- regex: "foo(.+)bar"
negate:
- FP1
This rule will not fire on the data below because the negative condition occurs at the same time as the positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:38 [emerg] FP1
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 25-example.log | preq -r ./25-negate-options-1x1.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.30K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [918B in 0s; 5.56MB/s]
Matching lines done! [13 lines in 0s; 77.38K lines/s]
If the negative condition occurs at a different time than the positive condition, the rule will now fire.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] FP1
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 25-example-new-negate-time.log | preq -r ./25-negate-options-1x1.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.61K rules/s]
Problems detected done! [1 in 0s; 2.51K/s]
Reading stdin done! [918B in 0s; 5.67MB/s]
negate-options-1x1 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [13 lines in 0s; 78.31K lines/s]
Match Width
The default behavior of a negative condition is it cannot occur between the first and last positive condition. This period of time between the first and last occurrence of a positive condition is referred to as its match width.
The negate option window
modifies the default behavior of negative conditions. It extends the time beyond the width of the positive matches. When defined, a negate window
adds the specified amount of time to the width of the match that occurred.
rules:
- cre:
id: negate-window
rule:
set:
event:
source: kafka
match:
- regex: "foo(.+)bar"
negate:
- value: FP1
window: 5s
This rule will no longer fire on the data above (26-example.log
) because the negative condition cannot happen for up to 5s seconds after the positive condition.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [emerg] FP1
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 26-example.log | preq -r ./26-negate-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.94K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [918B in 0s; 5.16MB/s]
Matching lines done! [13 lines in 0s; 68.78K lines/s]
This rule no longer matches because:
- The positive condition occurs at
12:07:38
on line 5 in26-example.log
- The negative condition occurs 5 seconds later at
12:07:43
on line 8 in26-example.log
If the negative condition occurs outside of the 5 second negate window
, then the rule will fire again.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:44 [emerg] FP1 happens 6 seconds later so the rule fires
2019/02/05 12:07:47 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:48 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:49 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
cat 26-example-moved-negative.log | preq -r ./26-negate-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.08K rules/s]
Problems detected done! [1 in 0s; 2.00K/s]
Reading stdin done! [960B in 0s; 5.33MB/s]
Matching lines done! [13 lines in 0s; 70.65K lines/s]
negate-window critical [1 hits @ 2019-02-05T06:07:38-06:00]
Multiple positive conditions width
When more than one positive condition is used with a negate window
, the width of the positive matches—the period of time between the first and last match—will be added to the negate window
when no other negate options are expressed.
rules:
- cre:
id: negate-window-2
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP2
window: 18s
In the example data below:
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [emerg] FP1
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:08:00 [emerg] FP2
The width of these positive conditions is 4s:
foo(.+)bar
occurs at12:07:38
b(.+)az
occurs at12:07:42
4 seconds later
A negate window
of 18s means the negative condition cannot occur within 22s after the first positive condition when the width of the positive conditions is 4s and the negate window
is an additional 18s.
Because "FP2"
occurs 22s after the first positive condition, the rule will not fire.
cat 27-example.log | preq -r ./27-negate-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.90K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [886B in 0s; 8.60MB/s]
Matching lines done! [12 lines in 0s; 108.11K lines/s]
If the width of the positive conditions is smaller, then the rule will fire.
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [emerg] FP1
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:08:00 [emerg] FP2
Because the match width
is 3s in the data above, the rule will now fire. The negative condition now cannot occur within 21s of the first positive condition when the match width
is 3s and the negate window
is an additional 18s. Because "FP2"
occurs 22s after the first positive condition, the rule will fire.
cat 27-example-smaller.log | preq -r 27-negate-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.02K rules/s]
Problems detected done! [1 in 1ms; 1.00K/s]
Reading stdin done! [886B in 0s; 3.90MB/s]
Matching lines done! [12 lines in 0s; 52.40K lines/s]
negate-window-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
Similarly, if the negate window
is decreased, then the rule will fire again if the match window
stays the same.
rules:
- cre:
id: negate-window-shorter
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP2
window: 17s
cat 27-example.log | preq -r 27-negate-window-shorter.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 1.93K rules/s]
Problems detected done! [1 in 0s; 1.87K/s]
Reading stdin done! [886B in 0s; 4.57MB/s]
Matching lines done! [12 lines in 0s; 60.30K lines/s]
negate-window-2 critical [1 hits @ 2019-02-05T06:07:38-06:00]
This new negate window
means the negative condition cannot occur within 21s of the first positive condition when the match width
is 4s (in 27-example.log
). Because "FP2"
occurs 22s after the first positive condition, the rule will fire.
Anchor
The negate option anchor
may be used to change the relative positive condition from which a negate window
is measured. This is useful when the negative condition has a known dependency on a specific positive term.
Recall the negate window
defines the time a negative condition cannot occur as the width
of the positive conditions plus the additional negate window
. By default, this window
of time is relative to the first positive condition (or anchor: 0
).
Use anchor
to change when the relative negative window
begins. The default negate window
is relative to the first positive condition (i.e. when anchor: 0
).
To change the anchor
to start the negate window
after the second positive condition:
rules:
- cre:
id: negate-anchor
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP2
window: 17s
anchor: 1
2019/02/05 12:07:37 [notice] 1629#1629: signal process started
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:43 [emerg] FP1
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:08:00 [emerg] FP2
The negative condition cannot occur 21s after the second positive condition (anchor: 1
):
- The match
width
of time between the first and last positive condition is 4s - The second positive condition
"test"
occurs at12:07:39
- 4s (match
width
) + 17s (negatewindow
) = 21s - The negative condition
"FP2"
occurs 21s later at12:08:00
(within the new total negatewindow
of 21s)
Because the negative condition occurs within the total negate window
anchored on the second positive condition, this rule does not fire.
cat 28-example.log | preq -r ./28-negate-anchor-0.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 945 rules/s]
Problems detected done! [0 in 1ms; 0/s]
Reading stdin done! [918B in 0s; 5.46MB/s]
Matching lines done! [13 lines in 0s; 76.47K lines/s]
Slide
Use the negate option slide
to shift the total negate window
to the left to define when negative conditions cannot happen before positive conditions.
rules:
- cre:
id: negate-slide
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP1
slide: -8s
This rule moves the negate window
to the left of the first positive condition (anchor: 0
) by 8s.
2019/02/05 12:07:30 [notice] FP1
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:08:00 [emerg] FP2
This rule will not fire because the negative condition "FP1"
occurs 8s before the first positive condition (within the total negate window
that is now shifted to the left by 8s using slide
).
cat 29-example.log | preq -r 29-negate-slide.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.44K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [824B in 0s; 5.84MB/s]
Matching lines done! [11 lines in 0s; 78.57K lines/s]
If anchor
is added to slide
the negate window
on the second positive condition, the rule will fire.
rules:
- cre:
id: negate-slide-anchor
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP1
slide: -8s
anchor: 1
cat 29-example.log | preq -r 29-negate-slide-anchor-1.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.16K rules/s]
Problems detected done! [1 in 1ms; 1.14K/s]
Reading stdin done! [824B in 0s; 4.60MB/s]
negate-slide-anchor critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [11 lines in 0s; 59.14K lines/s]
The negate option window
can be added to increase the total negate window
in a slide
.
rules:
- cre:
id: neg-all-opts
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP1
slide: -9s
anchor: 1
window: 1s
- The match
width
is 4s in29-example.log
- The additional negate
window
is 1s - The total negate
window
is 4s + 1s = 5s - A slide of -9s anchored on the second positive condition starts the total negate
window
of 5s at12:07:30
- A negative condition cannot occur between
12:07:30
and12:07:35
(+5s) when the second positive condition occurs at12:07:39
The rule will not fire since the negative condition occurs at 12:07:30
.
cat 29-example.log | preq -r 29-negate-slide-anchor-1-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.57K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [824B in 0s; 5.68MB/s]
Matching lines done! [11 lines in 0s; 74.83K lines/s]
If the negative condition moves to 12:07:36
, then the rule will fire because it is now outside of the shifted window before the positive terms.
2019/02/05 12:07:36 [notice] FP1
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:08:00 [emerg] FP2
cat 29-example-fp-moved.log | preq -r ./29-negate-slide-anchor-1-window.yaml -d -N
Example output
Parsing rules done! [1 rules in 1ms; 1.34K rules/s]
Problems detected done! [1 in 1ms; 1.35K/s]
Reading stdin done! [824B in 0s; 5.25MB/s]
neg-all-opts critical [1 hits @ 2019-02-05T06:07:38-06:00]
Matching lines done! [11 lines in 0s; 69.18K lines/s]
Absolute
Use the negate option absolute
to avoid adding the match width
to the total negate window
and instead use only the negate window
specified in negative condition. This is useful when the match width
is unpredictable.
rules:
- cre:
id: negate-absolute
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP2
window: 20s
absolute: true
This rule creates absolute
window of 20s anchored by default to the first positive term.
2019/02/05 12:07:30 [notice] FP1
2019/02/05 12:07:37 [error] 1629#1629: open() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:37 [emerg] 1655#1655: bind() just kidding false alarm this is normal
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to 0.0.0.0:80 failed (98: Address already in use)
2019/02/05 12:07:38 [emerg] 1655#1655: bind() to foo bar
2019/02/05 12:07:39 [emerg] 1655#1655: bind() to test
2019/02/05 12:07:40 [emerg] 1655#1655: bind() to 0.0.0.0:444 failed (98: Address already in use)
2019/02/05 12:07:41 [emerg] 1655#1655: bind() to [::]:444 failed (98: Address already in use)
2019/02/05 12:07:42 [emerg] 1655#1655: still could not bind() to baaaz
2019/02/05 12:07:46 [alert] 1631#1631: unlink() "/run/nginx.pid" failed (2: No such file or directory)
2019/02/05 12:07:58 [emerg] FP2
Because the negative condition "FP2"
occurs 20s after the first positive condition, this rule does not fire.
cat 30-example.log | preq -r 30-negate-absolute.yaml -d -N
Example output
Parsing rules done! [1 rules in 0s; 2.58K rules/s]
Problems detected done! [0 in 0s; 0/s]
Reading stdin done! [824B in 0s; 7.85MB/s]
Matching lines done! [11 lines in 0s; 100.00K lines/s]
Common Pitfalls
Anchor index cannot exceed number of positive conditions
Do not use an anchor
index that exceeds the range of positive conditions.
rules:
- cre:
id: negate-bad-anchor
rule:
set:
event:
source: kafka
window: 5s
match:
- regex: "foo(.+)bar"
- value: "test"
- regex: "b(.+)az"
negate:
- value: FP2
window: 20s
anchor: 3 # the range of the three positive anchors is 0, 1, and 2
$ cat *.log | preq -r 31-bad-negate-anchor.yaml -d -N
Rules error: anchor out of range
Data Sources
A rule defines an abstract data source
to target an addressable named data type (e.g. log, metric, trace, or event).
rules:
- cre:
id: string-example-1
rule:
set:
event:
source: kafka
match:
- value: "[emerg] 1655#1655: still could not bind()"
Because the location and address of data sources vary based on the environment (e.g. Kubernetes vs. virtual machines vs. laptops and servers) and distribution (Docker Hub vs. Bitnami vs. Quay.io), CRE rules are created to target a data source
abstraction that is translated by the problem detector to the actual source's location in the environment.
The preq
problem detector supports targeting log files via stdin
(all abstract data sources) or by or addressed from the file system. Refer to Prequel for addressing containers or additional data types.
See Data Sources for more information.
Nested Conditions
One or more nested conditions from another sequence
or set
may be used as as a condition of another set
or sequence
. Nested expressions enable complex positive and negative conditions to be created across distributed data sources. It also enables correlations
on two or more conditions to test whether they share attributes in common. For example, correlations on conditions by host
evaluate to true only when all conditions occur on the same machine.
Nested conditions and correlations
are supported in Prequel.
rules:
- cre:
id: nested-example
rule:
sequence:
window: 30s
correlations:
- hostname
order:
- term1
- term2
negate:
- term3
terms:
term1:
sequence:
window: 10s
event:
source: rabbitmq
origin: true
order:
- value: Discarding message
count: 10
- Mnesia overloaded
negate:
- SIGTERM
term2:
sequence:
window: 5s
correlations:
- container_id
order:
- sequence:
window: 1s
event:
source: nginx
order:
- error message
- shutdown
- set:
event:
source: nginx
match:
- 90%
- set:
event:
source: k8s
match:
- field: "reason"
value: "Killing"
term3:
set:
event:
source: k8s
match:
- field: "reason"
value: "NodeShutdown"
The rule above detects the following:
- At the top level the rule looks for two positive conditions and resets on one negative condition.
- The first positive condition is a
sequence
of 11 positive conditions and 1 negative condition inrabbitmq
. - The second positive condition is another
sequence
of three positive conditions.- The first positive condition is a
sequence
innginx
of two positive conditions,error message
andshutdown
. - The second positive condition is a
set
innginx
that matches on90%
- The third positive condition is another
set
that matches a KubernetesKilling
event - The
correlation
on these conditions means all three positive conditions must share the samecontainer_id
to match
- The first positive condition is a
- The top level rule also looks for one negative condition
- A Kubernetes
NodeShutdown
event
- A Kubernetes
- The first positive condition is a
Origin
When using nested conditions, the rule author must specify which expression on an abstract data source constitutes the origin
event that will take the blame for the overall detection. The origin
is implied when nested conditions are not used since the rule is only targeting one data source.
Correlations
A correlation
is used in nested conditions to add additional criteria to the match. The following fields may be used in a correlation
expression:
Field | Description |
---|---|
imageUrl | The container's image_url |
containerName | The name of the container |
containerId | The container's unique container runtime ID |
podName | The name of the Kubernetes pod |
filepath | The path to the data on the file system |
processName | The name of the process |
namespace | The Kubernetes namespace |
machineId | The host's unique machine ID (see https://man7.org/linux/man-pages/man5/machine-id.5.html) |
hostname | The fully qualified DNS name of the machine |
workload | The name of the Kubernetes service, statefulset, daemonset, or deployment |