What would be the best method to tail a file in Clojure? I haven\'t come across any utilities that would help do so, but ideas on how to build one would be appreciated!
You can use RandomAccessFile
to seek directly to the end of the file and search for linebreaks from there. Not as elegant and short as the take-last
approach, but also not O(n)
which might matter for big file sizes.
No solution for tail -f
, though. Some inspiration might be found in JLogTailer.
Something like:
(take-last 10 (line-seq (clojure.contrib.io/reader "file")))
As kotarak stated, you could use RandomAccessFile to seek to the end of the File. Unfortunately you have to busy-wait/sleep for changes.
Using a lazy sequence you can process the lines "on-the-fly":
(import java.io.RandomAccessFile)
(defn raf-seq
[#^RandomAccessFile raf]
(if-let [line (.readLine raf)]
(lazy-seq (cons line (raf-seq raf)))
(do (Thread/sleep 1000)
(recur raf))))
(defn tail-seq [input]
(let [raf (RandomAccessFile. input "r")]
(.seek raf (.length raf))
(raf-seq raf)))
; Read the next 10 lines
(take 10 (tail-seq "/var/log/mail.log"))
Update:
Something like tail -f /var/log/mail.log -n 0, using doseq, so the changes are actually consumed.
(doseq [line (tail-seq "/var/log/mail.log")] (println line))