I'm discovering/learning Clojure with Riemann and I have written the following code to aggregate my CPU metrics per host :
(streams
(by [:host]
smap (aggregate-cpu-metrics "user" folds/mean)
smap (aggregate-cpu-metrics "nice" folds/mean)
smap (aggregate-cpu-metrics "system" folds/mean)
smap (aggregate-cpu-metrics "idle" folds/mean)
smap (aggregate-cpu-metrics "wait" folds/mean)
smap (aggregate-cpu-metrics "interrupt" folds/mean)
smap (aggregate-cpu-metrics "softirq" folds/mean)
smap (aggregate-cpu-metrics "steal" folds/mean)))
(defn aggregate-cpu-metrics
[name, aggr]
(where (service (re-pattern (str "cpu-[0-9]+ " name)))
(coalesce 10
(smap aggr
(with :service (str "cpu-average " name) reinject)))))
To explain the code a little bit, I'm receiving events like these :
- :service "cpu-0 idle" :metric 58.23
- :service "cpu-1 idle" :metric 98.11
- :service "cpu-2 idle" :metric 12.23
And my goal is to calculate the average and to reinject this event in riemann :
- :service "cpu-average" :metric 56.19
It's working, that's not the problem. But as you can see in lines 3 to 10, there is a lot of duplicate code here. I'm looking for a way to refactor this code, but I'm stuck.
I would like to define a vector with my metrics names :
(def cpu-metrics ["user", "nice", "system", "idle", "interrupt", "softirq", "steal"])
...and to use it to call smap(aggregate-cpu-metrics...
But I don't know how to do that. I've tried map or doseq, but without any success.
How would you do it ?
(Update / Solution) :
Here is my refactored version, after reading Arthur's answer.
(streams
(where
(service #"^cpu-[0-9]+ ")
(adjust
[:service #(clojure.string/replace % #"^cpu-[0-9]+" "cpu-average")]
(by [:host :service]
(fixed-time-window 10 (smap folds/mean reinject))))))