Clojure Web服务中的基本日志记录未出现在控制台上

Owe*_* S. 5 logging clojure ring datomic

我正在按照本教程在我的Clojure Web应用程序中设置应用程序日志记录,我将用于一些Datomic实验.该教程建议我所要做的就是将Clojure的clojure.tools.logging库添加到我的项目在Leiningen中的依赖项中,输出应该只显示在我的控制台上.但是,在启动应用程序时,我没有在控制台或其他地方看到任何日志记录输出.我究竟做错了什么?

这就是我的设置方式.我的Web堆栈是Ring/Compojure,作为嵌入式Jetty独立JAR(使用ring.adapter.jetty)运行,具有尚未使用数据库的虚拟API路由.

我的project.clj(注意:我正在评估Datomic的专业版,因此​​我在项目之外进行了GPG设置,以便正确下载受保护的JAR):

(defproject helloworld "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :min-lein-version "2.0.0"
  :repositories {
    "my.datomic.com" {:url "https://my.datomic.com/repo" :creds :gpg}}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [compojure "1.3.1"]
                 [ring/ring-defaults "0.1.2"]
                 [ring/ring-json "0.3.1"]
                 [ring/ring-defaults "0.1.2"]
                 [ring/ring-jetty-adapter "1.4.0"]
                 [org.clojure/tools.logging "0.3.1"]
                 [com.datomic/datomic-pro "0.9.5198" :exclusions [joda-time]]
                 [joda-time "2.8.1"]]
  :plugins [[lein-ring "0.8.13"]]
  :ring {:handler helloworld.handler/app}
  :main helloworld.core
  :aot [helloworld.core]
  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring-mock "0.1.5"]]}})
Run Code Online (Sandbox Code Playgroud)

文件src/helloworld/core.clj:

(ns helloworld.core
  (:require [clojure.tools.logging :as log]
            [ring.adapter.jetty :as jetty]
            [helloworld.handler :refer [app]])
  (:gen-class))

(defn -main [& args]
  (println "Hello, world!")
  (log/info "Service is running!")
  (jetty/run-jetty app {:port 8080}))
Run Code Online (Sandbox Code Playgroud)

Compojure应用程序和API处理程序src/helloworld/handler.clj:

(ns helloworld.handler
  (:require [clojure.tools.logging :as log]
            [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults api-defaults]]
            [ring.middleware.json :as json-middleware]
            [ring.util.response :refer [response]]))

(def dummy-entity {:id 1 :name "Hello, world!"})

(defroutes app-routes
  (GET "/" []
    (log/info "Getting all the things!")
    (response [dummy-entity]))
  (route/not-found "Not Found"))

(def app
  (->
    (wrap-defaults app-routes api-defaults)
    (json-middleware/wrap-json-body)
    (json-middleware/wrap-json-response)))
Run Code Online (Sandbox Code Playgroud)

这是我在尝试运行它时看到的内容(这也是在几次点击默认端点之后):

$ lein run
Hello, world!
Run Code Online (Sandbox Code Playgroud)

所以println肯定是有效的,但记录似乎并不存在.

Owe*_* S. 6

事实证明这里的问题包括Datomic库,即使我没有使用它!如果我删除了datomic-pro和joda-time依赖关系并重新运行,会发生以下情况:

$ lein run
2015-07-12 12:50:36.305:INFO::main: Logging initialized @1599ms
Hello, world!
Jul 12, 2015 12:50:38 PM clojure.tools.logging$eval18$fn__22 invoke
INFO: Service is running!
2015-07-12 12:50:38.167:INFO:oejs.Server:main: jetty-9.2.10.v20150310
2015-07-12 12:50:38.225:INFO:oejs.ServerConnector:main: Started ServerConnector@510a6f62{HTTP/1.1}{0.0.0.0:8080}
2015-07-12 12:50:38.226:INFO:oejs.Server:main: Started @3520ms
Jul 12, 2015 12:50:42 PM clojure.tools.logging$eval18$fn__22 invoke
INFO: Getting all the things!
Run Code Online (Sandbox Code Playgroud)

所以现在我也得到了一堆Jetty日志,以及我的app日志.

我认为问题是这样的:

  • Clojure的日志库选择了它最喜欢的日志记录后端.
  • 我正在研究的教程假设项目的依赖项(或任何传递依赖项!)中没有包含日志库,因此将选择最后一个默认值(java.util.logging).这将默认登录到控制台.
  • 然而,Datomic引入了SLF4J,这是Clojure日志库愉快地喜欢的.
  • 反过来,SLF4J没有任何日志记录适配器可供使用,因为我没有在项目的依赖项中指定任何.所以它选择了一个无操作的记录器.(谢谢,SLF4J.)

我通过对实际使用的记录器进行一些调试来验证这一点.我把它添加到-main:

(ns ...
  (require ...
           [clojure.tools.logging.impl :as log-impl]
           ...))
...
(let [logger (log-impl/get-logger log/*logger-factory* *ns*)]
    (println logger))
Run Code Online (Sandbox Code Playgroud)

这向我展示了一些属于SLF4J的NOOP记录器类的对象.

我通过在项目依赖项中添加适当的SLF4J适配器来修复.我选择使用Logback:

[com.datomic/datomic-pro "0.9.5198"
 :exclusions [joda-time org.slf4j/slf4j-nop org.slf4j/slf4j-log4j12]]
[ch.qos.logback/logback-classic "1.1.3"]
Run Code Online (Sandbox Code Playgroud)

要进行配置,我加的下列resources/logback.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
Run Code Online (Sandbox Code Playgroud)

那就解决了!

  • 感谢您提供详细的答案和解释! (4认同)