Skip to content

clojure.tools.logging with log4j2 backend writes to NREPL but not REPL buffer #3232

@vladprevi

Description

@vladprevi

Expected behavior

When logging with clojure.tools.logging with log4j2 backend set via relevant clojure.tools.logging.imlp factory I expect log messages both in NREPL and in REPL buffer. Note that we have cider-redirect-server-output-to-repl set to true and cider-nrepl loadded.

Actual behavior

Log messages turn up in the NREPL only buffer, but not in REPL

Potentially related tickets:
#524
#2138

but note that server output redirection to repl is set and works perfectly fine with e.g. logback backend.

Steps to reproduce the problem

With the following settings in your project.clj or similar in deps.edn:

Dependencies

[org.clojure/tools.logging "1.2.4"]
[org.apache.logging.log4j/log4j-api "2.18.0"]
[org.apache.logging.log4j/log4j-core "2.18.0"]
[org.apache.logging.log4j/log4j-1.2-api "2.18.0"]
[org.apache.logging.log4j/log4j-jcl "2.18.0"]
[org.apache.logging.log4j/log4j-jul "2.18.0"]
[org.apache.logging.log4j/log4j-slf4j-impl "2.18.0"]

JVM options that set the backend

:jvm-opts ["-Dlog4j2.configurationFile=log4j2.xml"
                  "-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory"]

Some simple config log4j2.xml in your classpath

Use below or e.g. this .properties example provided by clojure.tools.logging.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="5">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%date %level %logger %message%n%throwable"/>
      <!-- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> -->
    </Console>
  </Appenders>
  <Loggers>
    <Root level="info">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Jack in as usual and try this code:

(ns user (:require [clojure.tools.logging :as log]))

;; these will register in NREPL buffer but not your repl
(log/error "foo")
(log/info "foo")

;; confirm your setup was pulled in
(System/getProperty "log4j2.configurationFile")
(System/getProperty "clojure.tools.logging.factory")
(.name (clojure.tools.logging.impl/log4j2-factory))
(.name log/*logger-factory*)

(.toString
 (.getConfiguration
  (.getContext
   (clojure.tools.logging.impl/get-logger
    log/*logger-factory*
    *ns*))))

(.getState
 (.getConfiguration
  (.getContext
   (clojure.tools.logging.impl/get-logger
    log/*logger-factory*
    *ns*))))

Fun observation and experiments that may help

Our log4j2 setup above rescans itself for changes every 5 seconds. If you do in fact change that xml config you'll notice that those log messages will now appear in REPL as you'd expect. Because in prod when deployed logs will end up in STDOUT and we're only having trouble with our dev setup, I thought I'd be clever and trigger reloading our logger from e.g. user.clj with this:

(.stop
 (.getConfiguration
  (.getContext
   (clojure.tools.logging.impl/get-logger
    log/*logger-factory*
    *ns*))))

(.reconfigure
 (.getContext
  (clojure.tools.logging.impl/get-logger
   log/*logger-factory*
   *ns*)))

It does in fact fixes the problem and message start logging in the REPL buffer. It has fun consequences however: killing the REPL will kill Emacs. What fun :)

Environment & Version information

CIDER version information

;; Connected to nREPL server - nrepl://localhost:52598
;; CIDER 1.4.0 (Kyiv), nREPL 0.9.0
;; Clojure 1.11.1, Java 18.0.1

Lein / Clojure CLI version

Leiningen 2.9.8 on Java 18.0.1 OpenJDK 64-Bit Server VM

Emacs version

GNU Emacs 28.1 (build 2, x86_64-apple-darwin21.4.0, NS appkit-2113.40 Version 12.3.1 (Build 21E258)) of 2022-05-09

Operating system

Mac OS Monterey 12.3.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions