Update 3rd-party appenders (rough)

This commit is contained in:
Peter Taoussanis 2015-05-26 01:28:32 +07:00
parent 014faa7bab
commit 3c824d31da
7 changed files with 185 additions and 167 deletions

View File

@ -1,41 +1,44 @@
(ns taoensso.timbre.appenders.android (ns taoensso.timbre.appenders.3rd-party.android
"Android LogCat appender. Depends on the android runtime. This is a "Android LogCat appender. Requires Android runtime."
configuration for the timbre logging library"
{:author "Adam Clements"} {:author "Adam Clements"}
(:require [taoensso.timbre :as timbre] (:require [clojure.string :as str]
clojure.string)) [taoensso.timbre :as timbre]))
(defn make-logcat-appender (defn make-appender
"Returns an appender that writes to Android LogCat. Obviously only works if "Returns an appender that writes to Android LogCat. Obviously only works if
running within the Android runtime (device or emulator). You may want to running within the Android runtime (device or emulator). You may want to
disable std-out to prevent printing nested timestamps, etc." disable std-out to prevent printing nested timestamps, etc."
[& [appender-opts make-opts]] [& [appender-config make-config]]
(let [default-appender-opts {:enabled? true (let [default-appender-config
:min-level :debug}] {:enabled? true
(merge default-appender-opts appender-opts :min-level :debug}]
{:fn (fn [{:keys [level ns throwable message]}]
(let [output (format "%s %s - %s" timestamp
(-> level name clojure.string/upper-case)
(or message ""))]
(if throwable
(case level
:trace (android.util.Log/d ns output throwable)
:debug (android.util.Log/d ns output throwable)
:info (android.util.Log/i ns output throwable)
:warn (android.util.Log/w ns output throwable)
:error (android.util.Log/e ns output throwable)
:fatal (android.util.Log/e ns output throwable)
:report (android.util.Log/i ns output throwable))
(case level (merge default-appender-config appender-config
:trace (android.util.Log/d ns output) {:fn
:debug (android.util.Log/d ns output) (fn [data]
:info (android.util.Log/i ns output) (let [{:keys [level ?ns-str ?err_ msg_ timestamp_]} data
:warn (android.util.Log/w ns output) msg (or (force msg_) "")
:error (android.util.Log/e ns output) timestamp (force timestamp_)
:fatal (android.util.Log/e ns output) ns (or ?ns-str "")
:report (android.util.Log/i ns output)))))}))) output (format "%s %s - %s" timestamp
(-> level name str/upper-case)
msg)]
(def logcat-appender (if-let [throwable (force ?err_)]
"DEPRECATED: Use `make-logcat-appender` instead." (case level
(make-logcat-appender)) :trace (android.util.Log/d ns output throwable)
:debug (android.util.Log/d ns output throwable)
:info (android.util.Log/i ns output throwable)
:warn (android.util.Log/w ns output throwable)
:error (android.util.Log/e ns output throwable)
:fatal (android.util.Log/e ns output throwable)
:report (android.util.Log/i ns output throwable))
(case level
:trace (android.util.Log/d ns output)
:debug (android.util.Log/d ns output)
:info (android.util.Log/i ns output)
:warn (android.util.Log/w ns output)
:error (android.util.Log/e ns output)
:fatal (android.util.Log/e ns output)
:report (android.util.Log/i ns output)))))})))

View File

@ -1,18 +1,20 @@
(ns taoensso.timbre.appenders.irc (ns taoensso.timbre.appenders.3rd-party.irc
"IRC appender. Depends on https://github.com/flatland/irclj." "IRC appender. Requires https://github.com/flatland/irclj."
{:author "Emlyn Corrin"} {:author "Emlyn Corrin"}
(:require [clojure.string :as str] (:require [clojure.string :as str]
[irclj.core :as irc] [irclj.core :as irc]
[taoensso.timbre :as timbre])) [taoensso.timbre :as timbre]))
(defn default-fmt-output-fn (defn default-fmt-output-fn
[{:keys [level throwable message]}] [{:keys [level ?err_ msg_]}]
(format "[%s] %s%s" (format "[%s] %s%s"
(-> level name (str/upper-case)) (-> level name (str/upper-case))
(or message "") (or (force msg_) "")
(or (timbre/stacktrace throwable "\n") ""))) (if-let [err (force ?err_)]
(str "\n" (timbre/stacktrace err))
"")))
(def default-appender-opts (def default-appender-config
{:async? true {:async? true
:enabled? true :enabled? true
:min-level :info}) :min-level :info})
@ -38,38 +40,36 @@
(irc/message conn chan ">" line)))) (irc/message conn chan ">" line))))
(defn- make-appender-fn [irc-config conn] (defn- make-appender-fn [irc-config conn]
(fn [{:keys [ap-config] :as args}] (fn [data]
(when-let [irc-config (or irc-config (:irc ap-config))] (let [{:keys [appender-opts]} data]
(ensure-conn conn irc-config) (when-let [irc-config (or irc-config appender-opts)]
(let [fmt-fn (or (:fmt-output-fn irc-config) (ensure-conn conn irc-config)
default-fmt-output-fn)] (let [fmt-fn (or (:fmt-output-fn irc-config)
(send-message conn (:chan irc-config) (fmt-fn args)))))) default-fmt-output-fn)]
(send-message conn (:chan irc-config) (fmt-fn data)))))))
;;; Public ;;; Public
(defn make-irc-appender (defn make-appender
"Sends IRC messages using irc. "Sends IRC messages using irc.
Needs :irc config map in :shared-appender-config, e.g.: Needs :opts map in appender, e.g.:
{:host \"irc.example.org\" :port 6667 :nick \"logger\" {:host \"irc.example.org\" :port 6667 :nick \"logger\"
:name \"My Logger\" :chan \"#logs\"}" :name \"My Logger\" :chan \"#logs\"}"
[& [appender-opts {:keys [irc-config]}]] [& [appender-config {:keys [irc-config]}]]
(let [conn (atom nil)] (let [conn (atom nil)]
(merge default-appender-opts (merge default-appender-config appender-config
appender-opts {:conn conn
{:conn conn :fn (make-appender-fn irc-config conn)})))
:doc (:doc (meta #'make-irc-appender))
:fn (make-appender-fn irc-config conn)})))
(def irc-appender "DEPRECATED: Use `make-irc-appender` instead."
(make-irc-appender))
(comment (comment
(timbre/set-config! (timbre/merge-config! {:appenders {:irc (make-appender)}})
[:shared-appender-config :irc] (timbre/merge-config!
{:host "127.0.0.1" {:appenders
:nick "lazylog" {:irc
:user "lazare" {:opts
:name "Lazylus Logus" {:host "127.0.0.1"
:chan "bob"}) :nick "lazylog"
(timbre/set-config! [:appenders :irc] (make-irc-appender)) :user "lazare"
(timbre/log :error "A multiple\nline message\nfor you")) :name "Lazylus Logus"
:chan "bob"}}}})
(timbre/error "A multiple\nline message\nfor you"))

View File

@ -1,7 +1,9 @@
(ns taoensso.timbre.appenders.mongo (ns taoensso.timbre.appenders.3rd-party.mongo
"MongoDB appender. Depends on https://github.com/aboekhoff/congomongo." "MongoDB appender. Requires on https://github.com/aboekhoff/congomongo."
{:author "Emlyn Corrin"} {:author "Emlyn Corrin"}
(:require [somnium.congomongo :as mongo])) (:require [somnium.congomongo :as mongo]
[taoensso.timbre :as timbre]
[taoensso.encore :as encore]))
(def conn (atom nil)) (def conn (atom nil))
@ -21,26 +23,28 @@
:as config}] :as config}]
(let [selected-params (if logged-keys (let [selected-params (if logged-keys
(select-keys params logged-keys) (select-keys params logged-keys)
(dissoc params :ap-config)) (dissoc params :config :appender :appender-opts))
logged-params (if-let [t (:throwable selected-params)] logged-params (encore/map-vals #(str (force %)) selected-params)]
(assoc selected-params :throwable (str t))
selected-params)]
(mongo/with-mongo (ensure-conn config) (mongo/with-mongo (ensure-conn config)
(mongo/insert! collection logged-params)))) (mongo/insert! collection logged-params))))
(defn appender-fn [{:keys [ap-config] :as params}] (defn- make-appender-fn [make-config]
(when-let [mongo-config (:mongo ap-config)] (fn [data]
(log-message params mongo-config))) (let [{:keys [appender-opts]} data]
(when-let [mongo-config appender-opts]
(log-message data mongo-config)))))
(def mongo-appender (defn make-appender
{:doc (str "Logs to MongoDB using congomongo.\n" "Logs to MongoDB using congomongo. Needs :opts map in appender, e.g.:
"Needs :mongo config map in :shared-appender-config, e.g.: {:db \"logs\"
{:db \"logs\" :collection \"myapp\"
:collection \"myapp\" :logged-keys [:instant :level :msg_]
:logged-keys [:instant :level :message] :write-concern :acknowledged
:write-concern :acknowledged :server {:host \"127.0.0.1\"
:server {:host \"127.0.0.1\" :port 27017}}"
:port 27017}}") [& [appender-config make-config]]
:min-level :warn :enabled? true :async? true (let [default-appender-config
:rate-limit [1 1000] ; 1 entry / sec {:min-level :warn :enabled? true :async? true
:fn appender-fn}) :rate-limit [[1 1000]]}]
(merge default-appender-config appender-config
{:fn (make-appender-fn make-config)})))

View File

@ -1,8 +1,10 @@
(ns taoensso.timbre.appenders.rolling "Rolling file appender." (ns taoensso.timbre.appenders.3rd-party.rolling
"Rolling file appender."
{:author "Unknown - please let me know?"}
(:require [clojure.java.io :as io] (:require [clojure.java.io :as io]
[taoensso.timbre :as timbre]) [taoensso.timbre :as timbre])
(:import [java.text SimpleDateFormat] (:import [java.text SimpleDateFormat]
[java.util Calendar])) [java.util Calendar]))
(defn- rename-old-create-new-log [log old-log] (defn- rename-old-create-new-log [log old-log]
(.renameTo log old-log) (.renameTo log old-log)
@ -41,9 +43,11 @@
cal)) cal))
(defn- make-appender-fn [path pattern] (defn- make-appender-fn [path pattern]
(fn [{:keys [ap-config output instant]}] (fn [data]
(let [path (or path (-> ap-config :rolling :path)) (let [{:keys [instant appender-opts output-fn]} data
pattern (or pattern (-> ap-config :rolling :pattern) :daily) output (output-fn data)
path (or path (-> appender-opts :path))
pattern (or pattern (-> appender-opts :pattern) :daily)
prev-cal (prev-period-end-cal instant pattern) prev-cal (prev-period-end-cal instant pattern)
log (io/file path)] log (io/file path)]
(when log (when log
@ -52,20 +56,20 @@
(if (<= (.lastModified log) (.getTimeInMillis prev-cal)) (if (<= (.lastModified log) (.getTimeInMillis prev-cal))
(shift-log-period log path prev-cal)) (shift-log-period log path prev-cal))
(.createNewFile log)) (.createNewFile log))
(spit path (with-out-str (timbre/str-println output)) :append true) (spit path (with-out-str (println output)) :append true)
(catch java.io.IOException _)))))) (catch java.io.IOException _))))))
(defn make-rolling-appender (defn make-appender
"Returns a Rolling file appender. "Returns a Rolling file appender.
A rolling config map can be provided here as a second argument, or provided at A rolling config map can be provided here as a second argument, or provided in
:rolling in :shared-appender-config. appender's :opts map.
(make-rolling-appender {:enabled? true} (make-rolling-appender {:enabled? true}
{:path \"log/app.log\" {:path \"log/app.log\"
:pattern :daily}) :pattern :daily})
path: logfile path path: logfile path
pattern: frequency of rotation, available values: :daily (default), :weekly, :monthly" pattern: frequency of rotation, available values: :daily (default), :weekly, :monthly"
[& [appender-opts {:keys [path pattern]}]] [& [appender-config {:keys [path pattern]}]]
(let [default-appender-opts {:enabled? true :min-level nil}] (let [default-appender-config {:enabled? true :min-level nil}]
(merge default-appender-opts appender-opts (merge default-appender-config appender-config
{:fn (make-appender-fn path pattern)}))) {:fn (make-appender-fn path pattern)})))

View File

@ -1,10 +1,8 @@
(ns taoensso.timbre.appenders.rotor (ns taoensso.timbre.appenders.3rd-party.rotor
{:author "Yutaka Matsubara"} {:author "Yutaka Matsubara"}
(:import (:require [clojure.java.io :as io]
[java.io File FilenameFilter]) [taoensso.timbre :as timbre])
(:require (:import [java.io File FilenameFilter]))
[clojure.java.io :as io]
[taoensso.timbre :as t]))
(defn- ^FilenameFilter file-filter (defn- ^FilenameFilter file-filter
"Returns a Java FilenameFilter instance which only matches "Returns a Java FilenameFilter instance which only matches
@ -45,25 +43,27 @@
(reverse (map vector logs-to-rotate (iterate inc 1)))] (reverse (map vector logs-to-rotate (iterate inc 1)))]
(.renameTo log-file (io/file (format "%s.%03d" abs-path n)))))) (.renameTo log-file (io/file (format "%s.%03d" abs-path n))))))
(defn appender-fn [{:keys [ap-config output]}] (defn make-appender-fn [make-config]
(let [{:keys [path max-size backlog] (fn [data]
:or {max-size (* 1024 1024) (let [{:keys [appender-opts output-fn]} data
backlog 5}} (:rotor ap-config)] {:keys [path max-size backlog]
(when path :or {max-size (* 1024 1024)
(try backlog 5}} appender-opts]
(when (> (.length (io/file path)) max-size) (when path
(rotate-logs path backlog)) (try
(spit path (when (> (.length (io/file path)) max-size)
(str output "\n") (rotate-logs path backlog))
:append true) (spit path (str (output-fn data) "\n") :append true)
(catch java.io.IOException _))))) (catch java.io.IOException _))))))
(def rotor-appender (defn make-appender
{:doc (str "Simple Rotating File Appender.\n" "Simple Rotating File Appender.
"Needs :rotor config map in :shared-appender-config, e.g.: Needs :opts map in appender, e.g.:
{:path \"logs/app.log\" {:path \"logs/app.log\"
:max-size (* 512 1024) :max-size (* 512 1024)
:backlog 5}") :backlog 5}"
:min-level nil [& [appender-config make-config]]
:enabled? true (let [default-appender-config
:fn appender-fn}) {:min-level :warn :enabled? true}]
(merge default-appender-config appender-config
{:fn (make-appender-fn make-config)})))

View File

@ -1,10 +1,10 @@
(ns taoensso.timbre.appenders.socket (ns taoensso.timbre.appenders.3rd-party.socket
"TCP Socket appender. Depends on https://github.com/technomancy/server-socket." "TCP socket appender. Requires https://github.com/technomancy/server-socket."
{:author "Emlyn Corrin"} {:author "Emlyn Corrin"}
(:require [server.socket :refer [create-server]] (:require [server.socket :refer [create-server]]
[taoensso.timbre :refer [stacktrace]]) [taoensso.timbre :refer [stacktrace]])
(:import [java.net Socket InetAddress] (:import [java.net Socket InetAddress]
[java.io BufferedReader InputStreamReader PrintWriter])) [java.io BufferedReader InputStreamReader PrintWriter]))
(def conn (atom nil)) (def conn (atom nil))
@ -30,19 +30,23 @@
(defn ensure-conn [socket-config] (defn ensure-conn [socket-config]
(swap! conn #(or % (connect socket-config)))) (swap! conn #(or % (connect socket-config))))
(defn appender-fn [{:keys [ap-config prefix message throwable] :as params}] (defn make-appender-fn [make-config]
(when-let [socket-config (:socket ap-config)] (fn [data]
(let [c (ensure-conn socket-config)] (let [{:keys [appender-opts output-fn ?err_]} data]
(doseq [sock @(:connections c)] (when-let [socket-config appender-opts]
(let [out (PrintWriter. (.getOutputStream ^Socket sock))] (let [c (ensure-conn socket-config)]
(binding [*out* out] (doseq [sock @(:connections c)]
(println prefix message (let [out (PrintWriter. (.getOutputStream ^Socket sock))]
(stacktrace throwable)))))))) (binding [*out* out]
(println (output-fn data))))))))))
(def socket-appender (defn make-appender
{:doc (str "Logs to a listening socket.\n" "Logs to a listening socket.
"Needs :socket config map in :shared-appender-config, e.g.: Needs :opts map in appender, e.g.:
{:listen-addr :all {:listen-addr :all
:port 9000}") :port 9000}"
:min-level :trace :enabled? true [& [appender-config make-config]]
:fn appender-fn}) (let [default-appender-config
{:min-level :trace :enabled? true}]
(merge default-appender-config appender-config
{:fn (make-appender-fn make-config)})))

View File

@ -1,34 +1,37 @@
(ns taoensso.timbre.appenders.zmq (ns taoensso.timbre.appenders.3rd-party.zmq
"ØMQ appender. Requires https://github.com/zeromq/cljzmq" "ØMQ appender. Requires https://github.com/zeromq/cljzmq"
{:author "Angus Fletcher"} {:author "Angus Fletcher"}
(:require [zeromq.zmq :as zmq] (:require [zeromq.zmq :as zmq]
[taoensso.timbre :as timbre])) [taoensso.timbre :as timbre]))
(defn make-zmq-socket [context transport address port] (defn make-zmq-socket [context transport address port]
(doto (zmq/socket context :push) (doto (zmq/socket context :push)
(zmq/connect (format "%s://%s:%d" transport address port)))) (zmq/connect (format "%s://%s:%d" transport address port))))
(defn appender-fn [socket poller {:keys [ap-config output]}] (defn make-appender-fn [socket poller]
(loop [] (fn [data]
(zmq/poll poller 500) (let [{:keys [appender-opts output-fn]} data
(cond output (output-fn data)]
(zmq/check-poller poller 0 :pollout) (zmq/send-str socket output) (loop []
(zmq/check-poller poller 0 :pollerr) (System/exit 1) (zmq/poll poller 500)
:else (recur)))) (cond
(zmq/check-poller poller 0 :pollout) (zmq/send-str socket output)
(zmq/check-poller poller 0 :pollerr) (System/exit 1)
:else (recur))))))
(defn make-zmq-appender (defn make-appender
"Returns a ØMQ appender. Takes appender options and a map consisting of: "Returns a ØMQ appender. Takes appender options and a map consisting of:
transport: a string representing transport type: tcp, ipc, inproc, pgm/epgm transport: a string representing transport type: tcp, ipc, inproc, pgm/epgm
address: a string containing an address to connect to. address: a string containing an address to connect to.
port: a number representing the port to connect to." port: a number representing the port to connect to."
[& [appender-opts {:keys [transport address port]}]] [& [appender-config {:keys [transport address port]}]]
(let [default-appender-opts {:enabled? true (let [default-appender-config
:min-level :error {:enabled? true
:async? true} :min-level :error
:async? true}
context (zmq/zcontext) context (zmq/zcontext)
socket (make-zmq-socket context transport address port) socket (make-zmq-socket context transport address port)
poller (doto (zmq/poller context) poller (doto (zmq/poller context)
(zmq/register socket :pollout :pollerr))] (zmq/register socket :pollout :pollerr))]
(merge default-appender-opts (merge default-appender-config appender-config
appender-opts {:fn (make-appender-fn socket poller)})))
{:fn (partial appender-fn socket poller)})))