Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tailing a file in Clojure?

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!

Thanks.

like image 248
viksit Avatar asked Dec 02 '10 06:12

viksit


3 Answers

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))
like image 105
Jürgen Hötzel Avatar answered Nov 07 '22 06:11

Jürgen Hötzel


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.

like image 25
kotarak Avatar answered Nov 07 '22 06:11

kotarak


Something like:

(take-last 10 (line-seq (clojure.contrib.io/reader "file")))
like image 3
John Lawrence Aspden Avatar answered Nov 07 '22 08:11

John Lawrence Aspden