diff options
Diffstat (limited to 'src/clojure/contrib/javalog.clj')
-rw-r--r-- | src/clojure/contrib/javalog.clj | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/clojure/contrib/javalog.clj b/src/clojure/contrib/javalog.clj new file mode 100644 index 00000000..be662498 --- /dev/null +++ b/src/clojure/contrib/javalog.clj @@ -0,0 +1,97 @@ +;;; javalog.clj -- convenient access to java.util.logging in Clojure + +;; by Stuart Sierra <mail@stuartsierra.com> +;; April 8, 2008 + +;; Copyright (c) 2008 Stuart Sierra. All rights reserved. The use and +;; distribution terms for this software are covered by the Common +;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php) +;; which can be found in the file CPL.TXT at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + + +;; This file defines some convenience functions for using the Java +;; logging framework from Clojure. It is oriented towards simple +;; development and debugging rather than complex production +;; environments. + + + +(ns clojure.contrib.javalog + (:import + (java.util.logging Logger Level ConsoleHandler + FileHandler SimpleFormatter))) + +(def + #^{:tag Logger + :doc "The current java.util.logging.Logger. By default, the + global logger, modified by 'with-logger'."} + *logger* + (. Logger + (getLogger + (. Logger GLOBAL_LOGGER_NAME)))) + +(defmacro log-level + "Translates 'level' (a lower-case keyword) into a static field of + java.util.logging.Level, by name. + + Example: (log-level :severe) => java.util.logging.Level.SEVERE + + If 'level' is not a keyword, it is assumed to be a user-defined + instance of java.util.logging.Level and is returned unchanged." + [level] + (if (keyword? level) + `(. java.util.logging.Level + ~(symbol (. (name level) (toUpperCase)))) + level)) + +(defn root-logger + "Returns the root Logger instance." + ([] (root-logger *logger*)) + ([logger] (let [parent (. logger (getParent))] + (if parent + (recur parent) + logger)))) + +(defn set-console-log-level + "Attempts to set the level of the current logger and the root + ConsoleHandler to 'level' (a java.util.logging.Level). Useful for + debugging at the REPL." + [level] + (let [console-handler + (some (fn [h] (if (instance? ConsoleHandler h) h)) + (. (root-logger) (getHandlers)))] + (if console-handler + (do (. *logger* (setLevel level)) + (. console-handler (setLevel level))) + (throw (new Exception "No ConsoleHandler on root logger."))))) + +(defn add-log-file + "Attaches a log file, using SimpleFormatter, with the given level, + to the named logger. 'level' defaults to ALL. Note: multiple + invocations will create multiple log files, with numbers appended to + the names." + ([logger-name filename] + (add-log-file logger-name filename (. Level ALL))) + ([logger-name filename level] + (let [logger (. Logger (getLogger logger-name)) + handler (new FileHandler filename)] + (. handler (setFormatter (new SimpleFormatter))) + (. handler (setLevel level)) + (. logger (addHandler handler))))) + +(defmacro with-logger + "Executes 'body' with *logger* bound to a logger with the given name + and level. 'level' is expanded with 'log-level'." + [logger-name level & body] + `(binding [*logger* (. Logger (getLogger ~logger-name))] + (. *logger* (setLevel (log-level ~level))) + ~@body)) + +(defmacro log + "Logs a message to *logger*. 'level' is expanded with 'log-level'. + Example: (log :severe \"Bad argument: \" object)" + [level & strings] + `(. *logger* (log (log-level ~level) (str ~@strings)))) |