Nate needs to parse two different errors and takes some time to compose himself.
lazy-seq
.if
s or maybe an infinite cond
. Perhaps a complex state machine with backtracking?nil
if no error was found at the head of the sequence.or
block.or
block will try each one in turn until one matches and then that is the result.parse-next
, and the function that manages the lazy sequence is parse-all
.parse-all
has a call to lazy-seq
.parse-next
on the sequence.
cons
to add that value to the beginning of a recursive call to itself.nil
, it will recursively call itself with the rest
of the sequence, thus advancing the parsing forward one step.parse-all
function.Related episodes:
Clojure in this episode:
seq
, cons
, rest
lazy-seq
or
, cond
Code sample from this episode:
(ns devops.week-05
(:require
[devops.week-01 :refer [parse-line]]
[devops.week-02 :refer [process-log]]
[devops.week-03 :refer [sprinkle-errors-by-type]]
))
(defn parse-sprinkle
[lines]
(let [[first-line second-line] lines
[_whole donut-id] (some->> first-line :log/message (re-matches #"failed to add sprinkle to donut (\d+)"))
[_whole error] (some->> second-line :log/message (re-matches #"sprinkle fail reason: (.*)"))]
(when (and donut-id error)
(merge first-line
{:kind :sprinkle
:sprinkle/donut-id donut-id
:sprinkle/error error}))))
(defn parse-357-error
[lines]
(let [[first-line] lines
[_whole user] (some->> first-line :log/message (re-matches #"transaction failed while updating user ([^:]+): code 357"))]
(when user
(merge first-line
{:kind :code-357
:code-357/user user}))))
(defn parse-next
[lines]
(or (parse-357-error lines)
(parse-sprinkle lines)))
(defn parse-all
[lines]
(lazy-seq
(when (seq lines)
(if-some [found (parse-next lines)]
(cons found (parse-all (rest lines)))
(parse-all (rest lines))))))
(defn kind?
([kind]
#(kind? % kind))
([line kind]
(= kind (:kind line))))
(comment
(process-log "sample.log" #(->> % (map parse-line) parse-all (map :kind) doall))
(process-log "sample.log" #(->> % (map parse-line) parse-all (filter (kind? :sprinkle)) sprinkle-errors-by-type))
)
Log file sample:
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | transaction failed while updating user joe: code 357
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | failed to add sprinkle to donut 23948
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | sprinkle fail reason: should never happen
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | failed to add sprinkle to donut 94238
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | sprinkle fail reason: timeout exceeded threshold
2019-05-14 16:48:56 | process-Poster | INFO | com.donutgram.poster | transaction failed while updating user sally: code 357
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | failed to add sprinkle to donut 24839
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | sprinkle fail reason: too many requests
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | failed to add sprinkle to donut 19238
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | sprinkle fail reason: should never happen
2019-05-14 16:48:57 | process-Poster | INFO | com.donutgram.poster | transaction failed while updating user joe: code 357
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | failed to add sprinkle to donut 50493
2019-05-14 16:48:55 | process-Poster | INFO | com.donutgram.poster | sprinkle fail reason: unknown state