Идиоматический c построчный захват стандартного вывода в Clojure - PullRequest
2 голосов
/ 06 февраля 2020

У меня есть некоторый код (который я не могу изменить), который вызывает различные конечные точки API в течение нескольких секунд, печатая строки информации для вывода на каждом этапе. Вместо этого я хотел бы перенаправить строки, которые печатаются в стандартный вывод, в пользовательскую функцию ведения журнала.

Обычно, если бы мне пришлось вызывать код, побочные эффекты которого не контролируются при записи в стандартный вывод, я мог бы обернуть это в вызове with-out-str. В этом случае я ищу решение, которое позволило бы мне перехватывать каждую отдельную строку , когда она печатается , а не после того, как функция выполнена (это то, что with-out-str позволило бы мне сделать).

Есть ли идиоматический c способ сделать это, возможно, какой-то java.io.Writer, который вызывает обратный вызов при очистке каждой строки?

Я ищу что-то вроде этого:

(defn slowly-print-many-lines []
  (dotimes [i 10]
    (println "Printing line number" (inc i))
    (Thread/sleep 1000)))


(let [on-line-printed (fn [printed-line]
                        (my-logger/info printed-line))]
  (binding [*out* (callback-writer on-line-printed)]
    (slowly-print-many-lines)))

1 Ответ

1 голос
/ 06 февраля 2020

Вам нужно будет написать свой собственный класс оболочки PrintStream, затем использовать java.lang.System/setOut и setErr, чтобы переназначить значение System.out & System.err.

Вы можете увидеть связанный использование в библиотеке Tupelo Clojure macro with-system-out-str & friends, что отличается от Clojure with-out-str:

 (defmacro with-system-out-str
   "Evaluates exprs in a context in which JVM System/out is bound to a fresh
   PrintStream.  Returns the string created by any nested printing calls."
   [& body]
   `(let [baos# (ByteArrayOutputStream.)
          ps#   (PrintStream. baos#)]
      (System/setOut ps#)
      ~@body
      (System/setOut System/out)
      (.close ps#)
      (.toString baos#)))
...