Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Syslog back-end #301

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
:dependencies
[[org.clojure/clojure "1.5.1"]
[com.taoensso/encore "2.91.0"]
[net.java.dev.jna/jna "3.4.0"]
[io.aviso/pretty "0.1.33"]]

:plugins
Expand Down Expand Up @@ -44,6 +45,7 @@
[cheshire "5.6.3"]
[ymilky/franzy "0.0.1"]
[com.newrelic.agent.java/newrelic-agent "3.31.1"]
[net.java.dev.jna/jna "3.4.0"]
[raven-clj "1.5.0"]]}

:dev
Expand Down
96 changes: 96 additions & 0 deletions src/taoensso/timbre/appenders/3rd_party/syslog_appender.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
(ns taoensso.timbre.appenders.3rd-party.syslog-appender
"Requires https://github.com/java-native-access/jna"
{:author "Audrius Molis @audriu"
:inspired-by "https://github.com/joshrotenberg/brolog"}
(:require
[taoensso.timbre :as timbre])
(:import [com.sun.jna Function]))

(def ^:private timbre->syslog-priority
"Map timbre log levels to syslog levels"
{:trace 7 ;debug
:debug 7 ;debug
:info 6 ;info
;5 ;notice
:warn 4 ;warning
:error 3 ;err
;2 ;crit
:report 1 ;alert
:fatal 0 ;emerg
})

(defn- <<3 [n] (bit-shift-left n 3))

(def ^:private facility-map
{:log-kern (<<3 0)
:log-user (<<3 1)
:log-mail (<<3 2)
:log-daemon (<<3 3)
:log-auth (<<3 4)
:log-syslog (<<3 5)
:log-lpr (<<3 6)
:log-news (<<3 7)
:log-uucp (<<3 8)
:log-cron (<<3 9)
:log-authpriv (<<3 10)
:log-ftp (<<3 11)
:log-ntp (<<3 12)
:log-security (<<3 13)
:log-local0 (<<3 16)
:log-local1 (<<3 17)
:log-local2 (<<3 18)
:log-local3 (<<3 19)
:log-local4 (<<3 20)
:log-local5 (<<3 21)
:log-local6 (<<3 22)
:log-local7 (<<3 23)})

(def ^:private options
{:log-pid (byte 0x01) ;; log the pid
:log-cons (byte 0x02) ;; log to the console if errors in sending
:log-odelay (byte 0x04) ;; delay open until first call
:log-ndelay (byte 0x08) ;; don't delay open
:log-nowait (byte 0x10) ;; don't wait for console forks (deprecated)
:log-perror (byte 0x20) ;; log to stderr as well
})

(defn- openlog
[ident option facility]
(let [f (com.sun.jna.Function/getFunction "c" "openlog")]
(.invoke f Integer (to-array [ident option facility]))))

(defn- syslog
[priority format & args]
(let [f (com.sun.jna.Function/getFunction "c" "syslog")]
(.invoke f Integer (to-array (flatten [priority format args])))))

(defn- log-message [ident syslog-options facility data]
(openlog ident syslog-options facility)
(let [{:keys [level vargs]} data
priority (timbre->syslog-priority level)]
(syslog priority (str vargs))))

(defn syslog-appender
"Returns a syslog appender. All parameters are optional.
(journald-appender
{:ident \"my-app\"
:syslog-options bytemap of values from 'options' map.
:facility :log-user}})"
[config]
(let [{:keys [ident syslog-options facility]
:or {facility :log-user}} config
facility (facility-map facility)]
{:enabled? true
:async? true
:min-level nil
:output-fn :inherit
:fn (fn [data] (log-message ident syslog-options facility data))}))

(comment
(timbre/merge-config!
{:appenders
{:syslog-appender
(taoensso.timbre.appenders.3rd-party.syslog-appender/syslog-appender
{:ident "my-app"
:syslog-options (byte 0x03)
:facility :log-user})}}))