aboutsummaryrefslogtreecommitdiff
path: root/src/clojure
diff options
context:
space:
mode:
authorAlexander Taggart <alex.taggart@gmail.com>2009-08-03 23:50:22 -0700
committerTom Faulhaber <git_net@infolace.com>2009-08-04 10:35:01 -0700
commit6c95fe90829cc66f81345a011dc25fc487e4cf0b (patch)
tree0e350ee4b59630aba6fc24432ebe9ab06afe7dc8 /src/clojure
parentdcec88467e840c0120e9f27f2020636857692800 (diff)
Added level-specific convenience log macros. Improved documentation.
Diffstat (limited to 'src/clojure')
-rw-r--r--src/clojure/contrib/logging.clj170
1 files changed, 109 insertions, 61 deletions
diff --git a/src/clojure/contrib/logging.clj b/src/clojure/contrib/logging.clj
index 18489cb0..520fd14a 100644
--- a/src/clojure/contrib/logging.clj
+++ b/src/clojure/contrib/logging.clj
@@ -13,43 +13,44 @@
(ns
#^{:author "Alex Taggart, Timothy Pratley",
- :doc "Logging macros which delegate to a specific logging
- implementation. At runtime a specific implementation is selected from, in
- order, Apache commons-logging, log4j, and finally java.util.logging.
+ :doc
+ "Logging macros which delegate to a specific logging implementation. At
+ macro-expansion-time a specific implementation is selected from, in order,
+ Apache commons-logging, log4j, and finally java.util.logging.
- Logging levels are specified by clojure keywords corresponding to the
+ Logging levels are specified by clojure keywords corresponding to the
values used in log4j/commons-logging:
- :trace, :debug, :info, :warn, :error, :fatal
+ :trace, :debug, :info, :warn, :error, :fatal
- Logging occurs with the log macro which writes either directly or via an
- agent. By default direct logging is disabled, but can be enabled via the
- *allow-direct-logging* boolean ref. If log is invoked within a transaction it
- will always use an agent.
+ Logging occurs with the log macro, or the level-specific convenience macros,
+ which write either directly or via an agent. By default direct logging is
+ disabled, but can be enabled via the *allow-direct-logging* boolean atom. If
+ logging is invoked within a transaction it will always use an agent.
- The log macro will not evaluate its 'message' unless the specific logging
+ The log macros will not evaluate their 'message' unless the specific logging
level is in effect.
- Alternately, you can use the spy function when you have code that needs to be
- evaluated, and also want to output its result to the debug log.
+ Alternately, you can use the spy macro when you have code that needs to be
+ evaluated, and also want to output the code and its result to the debug log.
Unless otherwise specified, the current namespace (as identified by *ns*) will
- be used as the log-name (similar to how the java class name is usually used).
+ be used as the log-ns (similar to how the java class name is usually used).
- Use the enabled? function to write conditional code against the logging level
+ Use the enabled? function to write conditional code against the logging level
(beyond simply whether or not to call log, which is handled automatically).
- You can redirect all java writes of System.out and System.err to the log
- system by calling log-capture!. To rebind *out* and *err* to the log system
- invoke with-logs. In both cases a log-name (e.g., \"com.example.captured\")
+ You can redirect all java writes of System.out and System.err to the log
+ system by calling log-capture!. To rebind *out* and *err* to the log system
+ invoke with-logs. In both cases a log-ns (e.g., \"com.example.captured\")
needs to be specified to namespace the output."}
clojure.contrib.logging)
(defstruct #^{:doc
- "A struct to abstract the functionality common to all implementations.
+ "A struct to abstract the functionality common to all logging implementations.
The keys are as follows:
:name ; the name of the logging system used
- :get-log ; fn [name] to obtain a log by string name
+ :get-log ; fn [log-ns] to obtain a log by string namespace
:enabled? ; fn [log lvl] to check if a particular level is emabled
:write ; fn [log lvl msg ex] to a log a message"}
log-system
@@ -58,12 +59,12 @@
(defmacro commons-logging
"Creates a log-system struct using the Apache commons-logging API,
- if present; otherwise nil. End-users should not need to invoke this macro."
+ if present, otherwise nil. End-users should not need to invoke this macro."
[]
(try
(import (org.apache.commons.logging LogFactory Log))
- `(letfn [(get-log# [name#]
- (LogFactory/getLog name#))
+ `(letfn [(get-log# [log-ns#]
+ (LogFactory/getLog log-ns#))
(enabled?# [log# level#]
(condp = level#
:trace (.isTraceEnabled log#)
@@ -85,7 +86,7 @@
(defmacro log4j-logging
- "Creates a log-system struct using the log4j API, if present; otherwise nil.
+ "Creates a log-system struct using the log4j API, if present, otherwise nil.
End-users should not need to invoke this macro."
[]
(try
@@ -96,9 +97,9 @@
:warn Level/WARN
:error Level/ERROR
:fatal Level/FATAL}]
- (letfn [(get-log# [name#]
- (Logger/getLogger name#))
- (enabled?# [log# level#]
+ (letfn [(get-log# [log-ns#]
+ (Logger/getLogger log-ns#))
+ (enabled?# [log# level#]
(.isEnabledFor log# (levels# level#)))
(write# [log# level# msg# e#]
(if-not e#
@@ -120,8 +121,8 @@
:warn Level/WARNING
:error Level/SEVERE
:fatal Level/SEVERE}]
- (letfn [(get-log# [name#]
- (Logger/getLogger name#))
+ (letfn [(get-log# [log-ns#]
+ (Logger/getLogger log-ns#))
(enabled?# [log# level#]
(.isLoggable log# (levels# level#)))
(write# [log# level# msg# e#]
@@ -135,57 +136,61 @@
(defn do-log
"Logs the message immediately if the specific logging level is enabled. Use
the log macro in preference to this function."
- [system-ref level message throwable log-name]
+ [system-ref level message throwable log-ns]
(let [system @system-ref
- log ((system :get-log) log-name)]
+ log ((system :get-log) log-ns)]
(if ((system :enabled?) log level)
(do ((system :write) log level (force message) throwable)
system-ref))))
(def #^{:doc
- "The default log-system initialized to the first implementation found from:
- Apache commons-logging, log4j, java.util.logging."}
+ "An atom holding the default log-system initialized to the first
+ implementation found from: Apache commons-logging, log4j, java.util.logging."}
*log-system*
- (atom (some eval ['(commons-logging)
- '(log4j-logging)
- '(java-logging)])))
+ (atom (or (commons-logging)
+ (log4j-logging)
+ (java-logging)
+ (throw ; this should never happen in 1.5+
+ (RuntimeException.
+ "Valid logging implementation could not be found.")))))
(def #^{:doc
- "The default agent referecing *log-system*."}
+ "The default agent referencing *log-system*."}
*log-system-agent* (agent *log-system*))
(def #^{:doc
- "A flag indicating wether logging can be directly (as opposed to via an agent)
- when not operating from within a transaction. Defaults to false."}
+ "A boolean atom indicating whether direct logging (as opposed to via an agent)
+ is allowed when not operating from within a transaction. Defaults to false."}
*allow-direct-logging* (atom false))
(defmacro log
- "Logs a message, either directly or via an agent."
+ "Logs a message, either directly or via an agent. See also the level-specific
+ convenience macros."
([level message]
`(log ~level ~message nil))
([level message throwable]
`(log ~level ~message ~throwable (str *ns*)))
- ([level message throwable log-name]
+ ([level message throwable log-ns]
`(if (and @*allow-direct-logging*
(not (clojure.lang.LockingTransaction/isRunning)))
- (do-log *log-system* ~level (delay ~message) ~throwable ~log-name)
+ (do-log *log-system* ~level (delay ~message) ~throwable ~log-ns)
(send-off *log-system-agent*
- do-log ~level (delay ~message) ~throwable ~log-name))))
+ do-log ~level (delay ~message) ~throwable ~log-ns))))
(defn enabled?
- "Returns true if the specific logging level is enabled. This function should
- only be necessary if one needs to execute alternate code paths beyond whether
- the log should be written to."
+ "Returns true if the specific logging level is enabled. Use of this function
+ should only be necessary if one needs to execute alternate code paths beyond
+ whether the log should be written to."
([level]
(enabled? level (str *ns*)))
- ([level log-name]
+ ([level log-ns]
(let [sys @*log-system*]
- ((sys :enabled?) ((sys :get-log) log-name) level))))
+ ((sys :enabled?) ((sys :get-log) log-ns) level))))
(defmacro spy
@@ -198,7 +203,7 @@
(defn log-stream
"Creates a PrintStream that will output to the log. End-users should not need
to invoke this function."
- [level log-name]
+ [level log-ns]
(java.io.PrintStream.
(proxy [java.io.ByteArrayOutputStream] []
(flush []
@@ -206,25 +211,25 @@
(let [s (.trim (.toString this))]
(proxy-super reset)
(if (> (.length s) 0)
- (log level s nil log-name)))))
+ (log level s nil log-ns)))))
true))
(def #^{:doc
- "Used by log-capture! to maintain a reference to the original System.out and
- System.err streams."}
+ "A ref used by log-capture! to maintain a reference to the original System.out
+ and System.err streams."}
*old-std-streams* (ref nil))
(defn log-capture!
"Captures System.out and System.err, redirecting all writes of those streams
- to :info and :error logging, respectively. The specified log-name value will
+ to :info and :error logging, respectively. The specified log-ns value will
be used to namespace all redirected logging. NOTE: this will not redirect
output of *out* or *err*; for that, use with-logs."
- [log-name]
+ [log-ns]
(dosync
- (let [new-out (log-stream :info log-name)
- new-err (log-stream :error log-name)]
+ (let [new-out (log-stream :info log-ns)
+ new-err (log-stream :error log-ns)]
; don't overwrite the original values
(if (nil? @*old-std-streams*)
(ref-set *old-std-streams* {:out System/out :err System/err}))
@@ -233,7 +238,7 @@
(defn log-uncapture!
- "Restores System/out and System/err to their original values."
+ "Restores System.out and System.err to their original values."
[]
(dosync
(when-let [{old-out :out old-err :err} @*old-std-streams*]
@@ -244,12 +249,55 @@
(defmacro with-logs
"Evaluates exprs in a context in which *out* and *err* are bound to :info and
- :error logging, respectively. The specified log-name value will be used to
+ :error logging, respectively. The specified log-ns value will be used to
namespace all redirected logging."
- [log-name & body]
- (if (and log-name (seq body))
+ [log-ns & body]
+ (if (and log-ns (seq body))
`(binding [*out* (java.io.OutputStreamWriter.
- (log-stream :info ~log-name))
+ (log-stream :info ~log-ns))
*err* (java.io.OutputStreamWriter.
- (log-stream :error ~log-name))]
+ (log-stream :error ~log-ns))]
~@body)))
+
+(defmacro trace
+ "Logs a message at the trace level."
+ ([message]
+ `(log :trace ~message))
+ ([message throwable]
+ `(log :trace ~message ~throwable)))
+
+(defmacro debug
+ "Logs a message at the debug level."
+ ([message]
+ `(log :debug ~message))
+ ([message throwable]
+ `(log :debug ~message ~throwable)))
+
+(defmacro info
+ "Logs a message at the info level."
+ ([message]
+ `(log :info ~message))
+ ([message throwable]
+ `(log :info ~message ~throwable)))
+
+(defmacro warn
+ "Logs a message at the warn level."
+ ([message]
+ `(log :warn ~message))
+ ([message throwable]
+ `(log :warn ~message ~throwable)))
+
+(defmacro error
+ "Logs a message at the error level."
+ ([message]
+ `(log :error ~message))
+ ([message throwable]
+ `(log :error ~message ~throwable)))
+
+(defmacro fatal
+ "Logs a message at the fatal level."
+ ([message]
+ `(log :fatal ~message))
+ ([message throwable]
+ `(log :fatal ~message ~throwable)))
+