David Gueta
David Gueta

Reputation: 89

Log4j fail to discover Plugin when using SBT

I'm working on creating a custom Log4j plugin for my project using SBT 1.9.9 scalaVersion := "2.13.9"

When I specify packages="com.testserver" in the Log4j XML configuration, everything works correctly. However, this property is deprecated, and I'm trying to configure it without using packages, but I haven't been successful.

The main issue is that Log4j fails to locate the plugin, leading to the following error:

[info] ERROR StatusConsoleListener Appenders contains an invalid element or attribute "MetadataFileAppender"

I've tried several approaches, including following the recommended setup described in the https://logging.apache.org/log4j/2.x/manual/plugins.html

Here is the relevant part of my project configuration:

build.sbt

lazy val core = (project in file("core"))
  .settings(
    name := "core",
  )

lazy val server = (project in file("server"))
  .dependsOn(core)
  .settings(
    Compile / mainClass := Some("com.testserver.Hello"),
    libraryDependencies ++= Dependencies.log4j ++ Dependencies.allOthers,
      name := "server",
  )

lazy val root = (project in file("."))
  .dependsOn(server)
  .settings(

    Compile / run / fork := true,
    Compile / mainClass := Some("com.testserver.Hello"),
    libraryDependencies ++= Dependencies.log4j,
    javaOptions ++= Seq(
      "-Dlog4j.configurationFile=server/src/universal/conf/log4j2.xml",
    )
  )

Dependencies

    "org.log4s" %% "log4s" % "1.10.0",
    "org.apache.logging.log4j" % "log4j-slf4j-impl" % log4jVersion,
    "org.apache.logging.log4j" % "log4j-slf4j2-impl" % log4jVersion,
    "org.apache.logging.log4j" % "log4j-core" % log4jVersion ,
    "org.apache.logging.log4j" % "log4j-api" % log4jVersion

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration strict="true" status="info">

    <Properties>
        <Property name="logPattern" value="%d{dd-MM-yyyy HH:mm:ss.SSS} %msg%n"/>
        <Property name="logLocation" value="/tmp/logs"/>
    </Properties>
    <Appenders>
        <MetadataFileAppender name="MetadataFileAppender" foobar="test" location="${sys:logLocation}" />
        <Console name="STDOUT">
            <PatternLayout pattern="${logPattern}"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

and finally my Pluging

package com.testserver

import org.apache.logging.log4j.core.LogEvent
import org.apache.logging.log4j.core.appender.AbstractAppender
import org.apache.logging.log4j.core.config.{ Node}
import org.apache.logging.log4j.core.config.plugins.{Plugin, PluginAttribute, PluginFactory}

@Plugin(name = "MetadataFileAppender", category = Node.CATEGORY , printObject = true)
class MetadataFileAppender(name: String,  foobar: String,  location: String)
  extends AbstractAppender(name, null, null, false, Array.empty) {
  println(s"MetadataFileAppender created - my logic here ${name} ${foobar} ${location}}")
  def append(event: LogEvent): Unit = {}
}

object MetadataFileAppender {
  // Factory method to create the appender with file path and custom metadata content
  @PluginFactory
  def createAppender(
                      @PluginAttribute("name") name: String,
                      @PluginAttribute("foobar") foobar: String,
                      @PluginAttribute("location") location: String
                    ): MetadataFileAppender = {
    new MetadataFileAppender(name, foobar, location)
  }
}

Problem Summary The MetadataFileAppender plugin works fine if I include the deprecated packages="com.testserver" property in log4j2.xml. However, I need a solution that avoids using this deprecated property. The Log4j documentation provides guidelines for setting up plugin discovery with Gradle and Maven, but nothing specific for SBT, where this should theoretically work without additional setup.

What I've Tried Direct configuration: Followed the "right way" as per the Log4j documentation. Rechecking dependencies and imports: Ensured all Log4j dependencies are correctly specified. I tried a few Refactoring log4j2.xml: Verified XML syntax and attributes. Does anyone know the correct configuration for enabling plugin discovery in SBT without the packages property, or if additional settings are required in SBT to make this work?

I also tried a few workaround hacks, including adjusting the compiler setup and importing the sbt-assembly-log4j2 plugin from GitHub, but nothing has worked so far. more info: https://github.com/mpollmeier/sbt-assembly-log4j2 Any advice or insight would be greatly appreciated!

Upvotes: 1

Views: 68

Answers (1)

Ga&#235;l J
Ga&#235;l J

Reputation: 15090

The relevant log4j documentation states that:

Registering plugins are done by placing a Log4j plugin descriptor (i.e., Log4j2Plugins.dat) into the classpath. This file is generated using the PluginProcessor annotation processor at compile-time. You need to configure your build tool as follows to employ PluginProcessor by the Java compiler.

The documentation only gives example for Maven and Gradle but you need to do the same with SBT. There's nothing "magic" in SBT that would do this automatically.


So the question(s) you should be asking are:

  • how to run a Java annotation processors with sbt?
  • can we run a Java annotation processor over Scala code?

From what I can read, you'd be able to run a Java annotation processor over Java code with SBT but not over Scala code because it has to run with the javac compiler.


Related links:

Upvotes: 0

Related Questions