diff --git a/src/babashka/impl/timbre.clj b/src/babashka/impl/logging.clj similarity index 76% rename from src/babashka/impl/timbre.clj rename to src/babashka/impl/logging.clj index 803cf80b..a497531a 100644 --- a/src/babashka/impl/timbre.clj +++ b/src/babashka/impl/logging.clj @@ -1,9 +1,10 @@ -(ns babashka.impl.timbre +(ns babashka.impl.logging (:require [clojure.tools.logging] [clojure.tools.logging.impl :as impl] [sci.core :as sci] [taoensso.encore :as enc :refer [have]] - [taoensso.timbre :as timbre])) + [taoensso.timbre :as timbre] + [taoensso.timbre.appenders.core :as appenders])) ;;;; timbre @@ -59,7 +60,44 @@ {} (select-keys (ns-publics ns) ks))) -(def config (sci/new-dynamic-var '*config* timbre/*config* {:ns tns})) +(def atomic-println @#'appenders/atomic-println) + +(defn println-appender + "Returns a simple `println` appender for Clojure/Script. + Use with ClojureScript requires that `cljs.core/*print-fn*` be set. + :stream (clj only) - e/o #{:auto :*out* :*err* :std-err :std-out }." + + ;; Unfortunately no easy way to check if *print-fn* is set. Metadata on the + ;; default throwing fn would be nice... + + [& [{:keys [stream] :or {stream :auto}}]] + (let [stream + (case stream + :std-err timbre/default-err + :std-out timbre/default-out + stream)] + {:enabled? true + :async? false + :min-level nil + :rate-limit nil + :output-fn :inherit + :fn + (fn [data] + (let [{:keys [output_]} data + stream + (case stream + :auto (if (:error-level? data) @sci/err @sci/out) + :*out* @sci/out + :*err* @sci/err + stream)] + (binding [*out* stream] + (atomic-println (force output_)))))})) + +(def default-config (assoc-in timbre/*config* [:appenders :println] + (println-appender {:stream :auto}))) + +(def config (sci/new-dynamic-var '*config* default-config + {:ns tns})) (defn swap-config! [f & args] (apply sci/alter-var-root config f args)) @@ -71,11 +109,12 @@ 'info 'infof 'warn 'warnf 'error 'errorf '-log! 'with-level - 'println-appender 'spit-appender]) + 'spit-appender]) 'log! (sci/copy-var log! tns) '*config* config 'swap-config! (sci/copy-var swap-config! tns) - 'set-level! (sci/copy-var set-level! tns))) + 'set-level! (sci/copy-var set-level! tns) + 'println-appender (sci/copy-var println-appender tns))) ;;;; clojure.tools.logging diff --git a/src/babashka/main.clj b/src/babashka/main.clj index b7811121..6d297b48 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -23,6 +23,8 @@ [babashka.impl.error-handler :refer [error-handler]] [babashka.impl.features :as features] [babashka.impl.fs :refer [fs-namespace]] + [babashka.impl.logging :refer [timbre-namespace tools-logging-namespace + tools-logging-impl-namespace]] [babashka.impl.pods :as pods] [babashka.impl.pprint :refer [pprint-namespace]] [babashka.impl.process :refer [process-namespace]] @@ -33,8 +35,6 @@ [babashka.impl.socket-repl :as socket-repl] [babashka.impl.tasks :as tasks :refer [tasks-namespace]] [babashka.impl.test :as t] - [babashka.impl.timbre :refer [timbre-namespace tools-logging-namespace - tools-logging-impl-namespace]] [babashka.impl.tools.cli :refer [tools-cli-namespace]] [babashka.nrepl.server :as nrepl-server] [babashka.wait :as wait] diff --git a/test/babashka/logging_test.clj b/test/babashka/logging_test.clj new file mode 100644 index 00000000..219f8a30 --- /dev/null +++ b/test/babashka/logging_test.clj @@ -0,0 +1,71 @@ +(ns babashka.logging-test + (:require [babashka.fs :as fs] + [babashka.test-utils :as tu] + [clojure.edn :as edn] + [clojure.test :as t :refer [deftest is testing]] + [clojure.string :as str])) + +(def program + '(do + (ns dude) + (require '[clojure.tools.logging :as log]) + (require '[taoensso.timbre :as timbre]) + + (defn test-fn + [] + (log/debug "test ctl debug level") + (log/info "test ctl info") + (timbre/debug "test timbre debug level") + (timbre/info "test timbre info")) + + (println "before setting log level") + (test-fn) + + (alter-var-root #'timbre/*config* #(assoc %1 :min-level :info)) + + (println "after setting log level to :info") + (test-fn) + + (println "with-level :debug") + (timbre/with-level :debug + (test-fn)) + + (timbre/set-level! :debug) + (println "after setting log level to :debug") + (test-fn) + + (timbre/infof "Hello %s" 123) + (log/infof "Hello %s" 123) + + (timbre/swap-config! assoc-in [:appenders :spit] (timbre/spit-appender {:fname "/tmp/timbre.log"})) + (log/infof "Hello %s" 123))) + +(deftest logging-test + (let [res (tu/bb nil (pr-str program))] + (is (= 17 (count (re-seq #"\[dude:.\]" res)))) + (is (= 6 (count (re-seq #"DEBUG" res)))) + (is (= 11 (count (re-seq #"INFO" res))))) + (testing "println appender works with with-out-str" + (let [res (tu/bb + nil + (pr-str '(do + (require '[taoensso.timbre :as timbre] + '[clojure.string :as str]) + (str/includes? (with-out-str (timbre/info "hello")) "hello")))) + res (edn/read-string res)] + (is (true? res)))) + (testing "spit-appender" + (let [temp-file (-> (fs/create-temp-dir) + (fs/file "log.txt")) + program (pr-str '(do + (require '[taoensso.timbre :as timbre] + '[clojure.string :as str]) + (def appender (timbre/spit-appender {:fname "{{fname}}"})) + (timbre/swap-config! assoc-in [:appenders :spit] appender) + (str/includes? (with-out-str (timbre/info "hello")) "hello"))) + program (str/replace program "{{fname}}" (str temp-file)) + _ (tu/bb + nil + program) + res (slurp temp-file)] + (is (str/includes? res "hello")))))