incz.fnl (1717B)
1 (local { : base64 } (require :anoia)) 2 (local ll (require :lualinux)) 3 4 (fn index [str indexname] 5 (string.format "{\"index\":{\"_index\":%q}}\n%s" indexname str)) 6 7 (local crlf "\r\n") 8 9 (fn chunk [str] 10 (let [len (# str)] 11 (string.format "%x%s%s%s" len crlf str crlf))) 12 13 (fn http-header [host path auth] 14 (string.format 15 "POST %s HTTP/1.1\r 16 Host: %s\ 17 Authorization: basic %s 18 Transfer-Encoding: chunked\r 19 \r 20 " 21 path host 22 (let [b64 (base64 :url)] (b64:encode auth)))) 23 24 (fn format-timestamp [timestamp] 25 ;; I can't make zincsearch understand any epoch-based timestamp 26 ;; formats, so we are formatting dates as iso-8601 and damn the leap 27 ;; seconds :-( 28 (let [secs (- (tonumber (string.sub timestamp 1 16) 16) 29 (lshift 1 62)) 30 nano (tonumber (string.sub timestamp 16 24) 16) 31 ts (+ (* secs 1000) (math.floor (/ nano 1000000)))] 32 (.. (os.date "!%FT%T" secs) "." nano "Z"))) 33 34 (fn process-line [indexname hostname line] 35 (let [(timestamp service msg) (string.match line "@(%x+) (%g+) (.+)$")] 36 (-> 37 (string.format 38 "{%q:%q,%q:%q,%q:%q,%q:%q}\n" 39 "@timestamp" (format-timestamp timestamp) 40 :service service 41 :message msg 42 :host hostname) 43 (index indexname) 44 chunk))) 45 46 (fn run [] 47 (let [myhostname (with-open [h (io.popen "hostname" :r)] (h:read "l")) 48 (filename loghost credentials indexname) (table.unpack arg)] 49 50 (with-open [infile (assert (io.open filename :r))] 51 (ll.write 1 (http-header loghost "/api/_bulk" credentials)) 52 (while (case (infile:read "l") 53 line (ll.write 1 (process-line indexname myhostname line)))) 54 (ll.write 1 (chunk ""))) 55 (io.stderr:write (ll.read 0)))) 56 57 58 { : run }