Ep 034: Break the Mold

Play Episode

Christoph finds exceptional log lines and takes a more literal approach.

Related episodes:

Clojure in this episode:

Code sample from this episode:

(ns devops.week-06
  (:require
    [clojure.string :as string]
    [devops.week-02 :refer [process-log]]
    [devops.week-05 :refer [parse-357-error parse-sprinkle]]
    ))


(def general-re #"(\d\d\d\d-\d\d-\d\d)\s+(\d\d:\d\d:\d\d)\s+\|\s+(\S+)\s+\|\s+(\S+)\s+\|\s+(\S+)\s+\|\s(.*)")

(defn parse-line
  [line]
  (if-let [[whole dt tm thread-name level ns message] (re-matches general-re line)]
    {:raw/line whole
     :log/date dt
     :log/time tm
     :log/thread thread-name
     :log/level level
     :log/namespace ns
     :log/message message}
    {:raw/line line
     :log/message line}))

(defn bare-line?
  [line]
  (nil? (:log/date line)))

(defn parse-exception-info
  [lines]
  (let [first-line (first lines)
        [_whole classname] (some->> first-line :log/message (re-matches #"([^ ]+) #error \{"))]
    (when classname
      (let [error-lines (cons first-line (take-while bare-line? (rest lines)))
            error-str (string/join "\n" (map :log/message error-lines))]
        (merge first-line
               {:kind :error
                :error/class classname
                :log/message error-str})))))

(defn parse-next
  [lines]
  (or (parse-357-error lines)
      (parse-sprinkle lines)
      (parse-exception-info 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))))))


(comment
  (process-log "sample.log" #(->> % (map parse-line) parse-all doall))
  )

Log file sample:

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
2019-05-14 16:48:55 | process-Poster | INFO  | com.donutgram.poster | Poster #error {
 :cause "Failed to lock the synchronizer"
 :data {}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "Failed to lock the synchronizer"
   :data {}
   :at [process.poster$eval50560 invokeStatic "poster.clj" 40]}]
 :trace
 [[process.poster$eval50560 invokeStatic "poster.clj" 40]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 748]]}