Merge pull request #18 from emlyn/socket

TCP Socket Appender (emlyn)
This commit is contained in:
Peter Taoussanis 2013-06-14 20:37:42 -07:00
commit f3d704bc45
2 changed files with 69 additions and 1 deletions

View File

@ -154,6 +154,25 @@ Filter logging output by namespaces:
:chan "#logs"})
```
#### Socket ([server-socket](https://github.com/technomancy/server-socket)) appender
Listens on the specified interface (use :all for all interfaces, defaults to localhost if unspecified) and port. Connect with either of:
```
telnet localhost 9000
netcat localhost 9000
```
```clojure
;; [server-socket "1.0.0"] ; Add to project.clj dependencies
;; (:require [taoensso.timbre.appenders (socket :as socket-appender)]) ; Add to ns
(timbre/set-config! [:appenders :socket] socket-appender/socket-appender)
(timbre/set-config! [:shared-appender-config :socket]
{:listen-addr :all
:port 9000})
```
### Custom appenders
Writing a custom appender is dead-easy:
@ -179,7 +198,7 @@ See the `timbre/config` docstring for more information on appenders.
The usual recommendation for Clojure profiling is: use a good **JVM profiler** like [YourKit](http://www.yourkit.com/), [JProfiler](http://www.ej-technologies.com/products/jprofiler/overview.html), or [VisualVM](http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/index.html).
And these certainly do the job. But as with many Java tools, they can be a little hairy and often heavy-handed - especially when applied to Clojure. Timbre includes an alternative.
And these certainly do the job. But as with many Java tools, they can be a little hairy and often heavy-handed - especially when applied to Clojure. Timbre includes an alternative.
Let's add it to our app's `ns` declaration:

View File

@ -0,0 +1,49 @@
(ns taoensso.timbre.appenders.socket
"TCP Socket appender. Depends on https://github.com/technomancy/server-socket."
{:author "Emlyn Corrin"}
(:require [server.socket :refer [create-server]]
[taoensso.timbre :refer [stacktrace]])
(:import [java.net Socket InetAddress]
[java.io BufferedReader InputStreamReader PrintWriter]))
(def conn (atom nil))
(defn listener-fun [in out]
(loop [lines (-> in
(InputStreamReader.)
(BufferedReader.)
(line-seq))]
(when-not (re-find #"(?i)^quit" (first lines))
(recur (rest lines)))))
(defn on-thread-daemon [f]
(doto (Thread. ^Runnable f)
(.setDaemon true)
(.start)))
(defn connect [{:keys [port listen-addr]}]
(let [addr (when (not= :all listen-addr)
(InetAddress/getByName listen-addr))]
(with-redefs [server.socket/on-thread on-thread-daemon]
(create-server port listener-fun 0 ^InetAddress addr))))
(defn ensure-conn [socket-config]
(swap! conn #(or % (connect socket-config))))
(defn appender-fn [{:keys [ap-config prefix message throwable] :as params}]
(when-let [socket-config (:socket ap-config)]
(let [c (ensure-conn socket-config)]
(doseq [sock @(:connections c)]
(let [out (PrintWriter. (.getOutputStream ^Socket sock))]
(binding [*out* out]
(println prefix message
(stacktrace throwable))))))))
(def socket-appender
{:doc (str "Logs to a listening socket.\n"
"Needs :socket config map in :shared-appender-config, e.g.:
{:listen-addr :all
:port 9000}")
:min-level :trace :enabled? true :async? false
:max-message-per-msecs nil ; no rate limit by default
:fn appender-fn})