Clojure 中的惯用日志记录

a.k*_*a.k 6 logging functional-programming clojure

我是 clojure 的新手,想了解在 clojure 中登录的方法,来自命令式背景。在java生产程序中,我通常会在方法的开始结束处记录(调试/信息) ,如下所示:

public void foo(){
   logger.debug("starting method to embrace %s", rightIdioms);
   doSomething();
   logger.debug("successfully embraced %s idioms", idioms.length);
}
Run Code Online (Sandbox Code Playgroud)

我熟悉日志记录的优点/缺点,并且知道clojure 中可用的工具,

我还可以在上述方法中找到一些登录的缺点,这加深了我在非强制登录时感受到的紧张感:

  1. 日志记录是一种副作用,而 clojure 则力求无副作用。
  2. 更多代码行或“代码复杂性”:在 java 中 - 拥有大类很常见(getter、setter、构造函数),在 clojure 中,表达式返回值、记录“困难”过程并强化小函数和命名空间:(一个例子是需要从 if 更改为 if-let 或 if-do 来执行日志记录):

    (defn foo [x]
      (if (neg? x)
        (inc x)
        x))
    
    (defn foo [x]
      (if (neg? x)
        (let [new-x (inc x)] 
          (logger/debug (format "inc value, now %s" new-x)
          new-x))
        x))
    
    Run Code Online (Sandbox Code Playgroud)

clojure/tap我已经阅读了或 的日志记录tracing,但不确定我是否完全发现它有用。

在 clojure 中进行日志记录的方法或惯用方式是什么?

Bip*_*ill 0

日志记录不会对程序数据产生副作用,因此 Clojure 道德规范并不反对它。

为了避免重新构建函数来记录其输入和输出,一个快速的技巧是滥用前置条件和后置条件:

(defn foo [x]
  {:pre [(do (println "foo" x) 
             true)]
   :post [(do (println "foo" x "==>" %) 
              true)]}
  (if (neg? x)
    (inc x)
    x))
Run Code Online (Sandbox Code Playgroud)

true使得条件成功。否则,程序就会停止。

前置条件和后置条件记录在此处: https ://clojure.org/reference/special_forms#_fn_name_param_condition_map_expr_2

fooREPL 中的日志记录增强功能如下所示:

user> (foo -7)
foo -7
foo -7 ==> -6
-6
Run Code Online (Sandbox Code Playgroud)

  • “日志记录不会对程序数据产生副作用,因此 Clojure 道德规范不会反对它” 任何改变函数内部系统状态的行为都是副作用。所以日志记录是一个副作用。 (2认同)
  • @m0skit0,在 Clojure 中,我们只反对稍后会绊倒我们的副作用。Clojure 对函数纯度有相当自由的看法。例如,请参阅 Clojure 的 [瞬态数据结构](https://clojure.org/reference/transients) - “如果一棵树倒在树林里,它会发出声音吗?” - 以及 Clojure 自己的日志库 [clojure.tools.logging](https://github.com/clojure/tools.logging/)。 (2认同)