Welcome! Please see the About page for a little more info on how this works.

0 votes
in Leiningen by

Hi Everyone!

I have a wired issue with creating jar files using lein, I added a new log4j-layout-template-json to my project and add a JSON template for logging using org.clojure/tools.logging f everything was working well when I was running things locally but when I try to run the project from the jar file I keep getting this error

ERROR StatusConsoleListener Unable to locate plugin type for JsonTemplateLayout
ERROR StatusConsoleListener Unable to locate plugin for JsonTemplateLayout
ERROR StatusConsoleListener Could not create plugin of type class org.apache.logging.log4j.core.appender.ConsoleAppender for element Console: java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.config.plugins.util.PluginType.getElementName()" because "childType" is null
 java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.config.plugins.util.PluginType.getElementName()" because "childType" is null
    at org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor.findNamedNode(PluginElementVisitor.java:104)

So the project can't see the log4j-layout-template-json and I was able to make a working jar file by replacing /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat with the file from the plugin itself so seems like the file gets overridden and the lein can't understand this Java plugin pattern
So the question here is there a way to automate this process with Lein or moving to deps could solve the issue, thank you!
project.clj file:

(defproject aa "aa"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.11.3"]
                 [org.clojure/tools.logging "1.2.4"]
                 [org.clojure/tools.cli "0.3.1"]
                 [org.clojure/core.async "1.3.610"]
                 [clj-commons/clj-yaml "1.0.26"]
                 [com.google.guava/guava "31.1-jre"]    
                 [io.netty/netty-all "4.1.107.Final"]
                 [org.clojure/core.match "1.0.1"]
                 [com.github.ben-manes.caffeine/caffeine "3.1.8"]
                 ;;;; Logging
                 [org.apache.logging.log4j/log4j-slf4j-impl "2.20.0"] ;; libraries using SLF4J won't complain
                 [org.apache.logging.log4j/log4j-api "2.20.0"]
                 [org.apache.logging.log4j/log4j-core "2.20.0"]
                 [org.apache.logging.log4j/log4j-layout-template-json "2.20.0"]]

  :jvm-opts ["-Dlog4j2.configurationFile=resources/log4j2.properties"
             "-Dlog4j2.garbagefreeThreadContextMap=true"
             "-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory"]

  :test-selectors {:default (complement :integration)
                   :integration :integration}

  :main ^:skip-aot aa.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all
                       :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

Using this https://github.com/arctype-co/log4j2-plugins-cache plugin solves the issue for now but I want to know if there is a solution without including a new plugin

1 Answer

0 votes
by

If you depend on multiple libraries that each have their own plugins cache (the .dat file), you need to merge those as part of your build process -- which is what the log4j2-plugins-cache plugin is for, with Leiningen.

In log4j 3.x, they plan to do away with this cache file and use something more amenable to build tooling that doesn't require custom merging like this.

I had to write something similar for tools.build / build.clj for use with the Clojure CLI: https://github.com/seancorfield/build-uber-log4j2-handler

...