Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Clarify the relationship between where, where-event, and match.

(where expr) rewrites expr in complex ways, as well as binding
symbols like 'event, 'metric, and 'state. In cases where you want to
write a predicate without symbol capture, (where-event event-name expr)
allowed you to bind the event to an arbitrary symbol inside expr.

We already have a system for binding variables in scope: function
arguments. We also have a large library of functions which take events
and return truthy values. It made sense to consolidate these two into a
new stream: (where* f), which takes a *function* of an event instead of
an expression. (where*) does not rewrite its arguments, except to
provide (where)'s (else ...) blocks.

(where-event) is gone; (where*) provides all its functionality in a more
composable way.

(match) has been underappreciated for a while now. I've made it more
powerful by using the new Match protocol in riemann.common, which allows
it to apply functions, regexes, sets, and values as predicates for
matching aspects of an event. It should be a solid complement to
(where) with these changes.
  • Loading branch information...
commit 9a348bdaa151134317162255c4e36ccf5fba8e00 1 parent 4d1f932
@aphyr authored
Showing with 84 additions and 43 deletions.
  1. +33 −20 src/riemann/streams.clj
  2. +51 −23 test/riemann/test/streams.clj
View
53 src/riemann/streams.clj
@@ -671,16 +671,23 @@
(riemann.client/send-event client event)))
(defn match
- "Passes events on to children only when (f event) is equal to value. If f is
- a regex, uses re-matches?"
+ "Passes events on to children only when (f event) matches value, using
+ riemann.common/match. For instance:
+
+ (match :service nil prn)
+ (match :state #{\"warning\" \"critical\"} prn)
+ (match :description #\"error\" prn)
+ (match :metric 5 prn)
+ (match expired? true prn)
+ (match (fn [e] (/ (:metric e) 1000)) 5 prn)
+
+ For cases where you only care about whether (f event) is truthy, use (where
+ some-fn) instead of (match some-fn true)."
[f value & children]
(fn [event]
- (let [x (f event)]
- (when (if (= (class value) java.util.regex.Pattern)
- (re-matches? value x)
- (= value x))
- (call-rescue event children)
- true))))
+ (when (riemann.common/match value (f event))
+ (call-rescue event children)
+ true)))
; Shortcuts for match
;(defn description [value & children] (apply match :description value children))
@@ -985,18 +992,24 @@
(= 'else (first expr))))
exprs)))
-(defmacro where-event
- "Passes on events where expr is true, binding the provided symbol
- to the event during evaluation.
-
- ; Match a event which has expired.
- (where-event event (expired? event) ...)"
- [event-sym expr & children]
- (let [p (where-rewrite expr)]
- `(let [kids# [~@children]]
- (fn [event#]
- (when (let [~event-sym event#] ~p)
- (call-rescue event# kids#))))))
+(defmacro where*
+ "A simpler, less magical variant of (where). Instead of binding symbols in
+ the context of an expression, where* takes a function which takes an event.
+ When (f event) is truthy, passes event to children--and otherwise, passes
+ event to (else ...) children. For example:
+
+ (where* (fn [e] (< 2 (:metric e))) prn)
+
+ (where* expired?
+ (partial prn \"Expired\")
+ (else
+ (partial prn \"Not expired!\")))"
+ [f & children]
+ (let [[true-kids else-kids] (where-partition-clauses children)]
+ `(fn [event#]
+ (if (~f event#)
+ (call-rescue event# ~true-kids)
+ (call-rescue event# ~else-kids)))))
(defmacro where
"Passes on events where expr is true. Expr is rewritten using where-rewrite.
View
74 test/riemann/test/streams.clj
@@ -107,22 +107,31 @@
{:metric 1}]))))
(deftest match-test
- (let [r (ref nil)
- s (match :service "foo" (fn [e] (dosync (ref-set r e))))]
- (s {:service "bar"})
- (is (= nil (deref r)))
+ ; Regular strings.
+ (test-stream (match :service "foo")
+ [{}
+ {:service "bar"}
+ {:service "foo"}]
+ [{:service "foo"}])
- (s {:service "foo"})
- (is (= {:service "foo"} (deref r))))
-
- ; Regex
- (let [r (ref nil)
- s (match :service #"^f" (fn [e] (dosync (ref-set r e))))]
- (s {:service "bar"})
- (is (= nil (deref r)))
+ ; Sets
+ (test-stream (match :metric #{0 2})
+ [{}
+ {:metric 1}
+ {:metric 2}]
+ [{:metric 2}])
- (s {:service "foo"})
- (is (= {:service "foo"} (deref r)))))
+ ; Regexen
+ (test-stream (match :state #"^mi")
+ [{}
+ {:state "migas"}
+ {:state "other breakfast foods"}]
+ [{:state "migas"}])
+
+ ; Functions
+ (test-stream (match identity 2)
+ [1 2 3]
+ [2]))
(deftest tagged-all-test
(test-stream (tagged-all ["kitten" "cat"])
@@ -163,21 +172,40 @@
[{:tags ["meow" "bark"]}
{:tags ["meow"]}]))
-(deftest where-event-test
- (let [r (ref [])
- s (where-event event
- (or (= "good" (:service event))
- (< 2 (:metric event)))
- (fn [e] (dosync (alter r conj e))))
+(deftest where*-test
+ (test-stream (where* identity)
+ [true false nil 2]
+ [true 2])
+
+ (test-stream (where* expired?)
+ [{:time -1 :ttl 0.5}
+ {:time 0 :ttl 1}]
+ [{:time -1 :ttl 0.5}])
+
+ ; Complex closure with else clause
+ (let [good (atom [])
+ bad (atom [])
+ s (where* (fn [event]
+ (or (= "good" (:service event))
+ (< 2 (:metric event))))
+ (partial swap! good conj)
+ (else (partial swap! bad conj)))
events [{:service "good" :metric 0}
{:service "bad" :metric 0}
{:metric 1}
{:service "bad" :metric 1}
- {:service "bad" :metric 3}]
- expect [{:service "good" :metric 0}
{:service "bad" :metric 3}]]
+
+ ; Run stream
(doseq [e events] (s e))
- (is (= expect (deref r)))))
+
+ (is (= @good
+ [{:service "good" :metric 0}
+ {:service "bad" :metric 3}]))
+ (is (= @bad
+ [{:service "bad" :metric 0}
+ {:metric 1}
+ {:service "bad" :metric 1}]))))
(deftest where-field
(let [r (ref [])
Please sign in to comment.
Something went wrong with that request. Please try again.