閱讀965 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Clojure世界:日誌管理——clojure.tools.logging

   處理日誌是任何一個產品級的程序都需要仔細處理的模塊。在Java中,我們經常使用的是log4j就是一個日誌框架。在clojure裏,同樣有一套日誌框架——clojure.tools.logging,它不僅提供了常用的日誌輸出功能,還屏蔽了Java各種日誌框架之間的差異,如slf4j,commons-logging,log4j,java.util.logging等,讓你可以透明地使用這些框架來處理日誌。

名稱:clojure.tools.logging
主頁:https://github.com/clojure/tools.logging
依賴:
[org.clojure/tools.logging "0.2.3"]

<dependency>
  
<groupId>org.clojure</groupId>
  
<artifactId>tools.logging</artifactId>
  
<version>0.2.3</version>
</dependency>

使用:
(ns example.core
  (:use [clojure.tools.logging :only (info error)]))

(defn divide [x y]
  (try
    (info "dividing" x "by" y)
    (/ x y)
    (catch Exception ex       (error ex "There was an error in calculation"))))

常用宏和方法:
1.除了上麵例子的info和error宏,還可以包括warn,trace,debug,fatal等常用宏,分別對應相應的日誌級別。這些方法會自動判斷當前logger的級別是否有效,有效的前提下才會輸出日誌。也就是說在Java裏,你經常需要這樣:
if (logger.isDebugEnabled()) {
    logger.debug(x 
+ " plus " + y + " is " + (x + y));
}
在使用 tools.logging的時候是不需要的,因為這些宏幫你做了這個判斷。另外,我們在使用log4j的時候需要指定log的namespace,在tools.logging裏不需要,默認會取當前的namespace也就是*ns*。
最後,info還有個infof的方法,用於輸出格式化日誌:
(infof "%s is %d years old" "kid" 3)
日誌輸出:
2012-02-12 20:23:07,394 INFO  log: kid is 3 years old
其他方法也有類似的如warnf,debugf等。
2.spy宏,同時輸出表達式的form和結果,例如
(spy (+1 2))
輸出日誌
2012-02-12 20:11:47,415 DEBUG log: (+ 1 2)
=> 3

3.with-logs宏可以在將*out*和*err*流重定向到日誌的情況下求值表達式,例如:
(with-logs *ns* (prn "hello world"))
輸出日誌:
2012-02-12 20:17:32,592 INFO  log: "hello world"
with-logs需要明確指定log-ns,默認out的輸出級別是info,而err的級別是error,可以指定輸出級別(with-logs [*ns* :info :error] ......)

4.事務中(dosync中)的日誌輸出,tools.logging做了特殊處理,默認情況下當且僅當事務成功提交的時候並且日誌級別是warn或者info會通過agent異步寫入日誌。tools.logging定義了一個全局的agent——*logging-agent*。當判斷當前是在事務中調用log宏,並且日誌級別在集合*tx-agent-levels*內,就會在事務提交成功的時候將日誌發送給*logging-agent*異步處理。可以通過*tx-agent-levels*改變使用agent輸出日誌的級別範圍,默認是#{:info :warn}。還可以通過改變*force*變量來強製使用direct或者agent的方式輸出日誌,*force*可以為:agent或者:direct。
(binding [*force* :agent]
  (log :info 
"hello world"))
這裏特別使用了log宏,需要明確指定日誌級別為info。

5.默認日誌框架的是從classpath查找的,查找的順序是sl4j,commons-logging,log4j,java.util.logging,找到哪個可用就用哪個。如果你的classpath裏存在多個日誌框架,如同時存在sl4j和commons-logging,那麼如果你希望強製使用commons-logging,可以通過改變*logger-factory*變量來使用:
(ns example
  (:use [clojure.tools.logging.impl :only [cl
-factory]]))
(binding [
*logger-factory* (cl-factory)]
  (info 
"hello world"))

*logger-factory*是dynamic變量,可以通過binding改變(前麵提到的*force*等變量也一樣),如果不希望每次都用binding,而是全局改變,則需要特殊處理:
(alter-var-root (var *logger-factory*) (constantly (cl-factory)))

其他logger factory還包括slf4j-factory,log4j-factory,jul-factory。

6.每個日誌框架的配置跟使用java沒有什麼兩樣,比如你用log4j,就需要在classpath下放置一個log4j.properties等。如果你希望用編程的方式配置,可以使用clj-logging-config

文章轉自莊周夢蝶  ,原文發布時間2012-02-12

最後更新:2017-05-18 20:36:05

  上一篇:go  《KAFKA官方文檔》入門指南(五)
  下一篇:go  《KAFKA官方文檔》入門指南(四)