Remove log4j

This commit is contained in:
Eugene Yokota 2025-08-30 18:53:42 -04:00
parent 3c62eddd42
commit 683a559b37
8 changed files with 21 additions and 216 deletions

View File

@ -10,7 +10,7 @@ import com.eed3si9n.jarjarabrams.ModuleCoordinate
// ThisBuild settings take lower precedence, // ThisBuild settings take lower precedence,
// but can be shared across the multi projects. // but can be shared across the multi projects.
ThisBuild / version := { ThisBuild / version := {
val v = "2.0.0-SNAPSHOT" val v = "2.0.0-RC4-bin-SNAPSHOT"
nightlyVersion.getOrElse(v) nightlyVersion.getOrElse(v)
} }
ThisBuild / Utils.version2_13 := "2.0.0-SNAPSHOT" ThisBuild / Utils.version2_13 := "2.0.0-SNAPSHOT"
@ -146,6 +146,7 @@ def mimaSettingsSince(versions: Seq[String]): Seq[Def.Setting[?]] = Def settings
exclude[FinalMethodProblem]("sbt.internal.*"), exclude[FinalMethodProblem]("sbt.internal.*"),
exclude[IncompatibleResultTypeProblem]("sbt.internal.*"), exclude[IncompatibleResultTypeProblem]("sbt.internal.*"),
exclude[ReversedMissingMethodProblem]("sbt.internal.*"), exclude[ReversedMissingMethodProblem]("sbt.internal.*"),
exclude[DirectMissingMethodProblem]("sbt.Keys.extraLoggers"),
), ),
) )
@ -319,8 +320,6 @@ lazy val utilLogging = project
jline3Terminal, jline3Terminal,
jline3JNI, jline3JNI,
jline3Native, jline3Native,
log4jApi,
log4jCore,
disruptor, disruptor,
sjsonNewScalaJson.value, sjsonNewScalaJson.value,
), ),
@ -338,6 +337,8 @@ lazy val utilLogging = project
Test / fork := true, Test / fork := true,
mimaSettings, mimaSettings,
mimaBinaryIssueFilters ++= Seq( mimaBinaryIssueFilters ++= Seq(
exclude[MissingClassProblem]("sbt.internal.util.ConsoleAppenderFromLog4J"),
exclude[MissingClassProblem]("sbt.internal.util.Log4JConsoleAppender"),
), ),
) )
.configure(addSbtIO) .configure(addSbtIO)
@ -711,13 +712,13 @@ lazy val mainProj = (project in file("main"))
} }
}, },
libraryDependencies ++= libraryDependencies ++=
(Seq( Seq(
scalaXml, scalaXml,
sjsonNewScalaJson.value, sjsonNewScalaJson.value,
sjsonNewCore.value, sjsonNewCore.value,
launcherInterface, launcherInterface,
caffeine, caffeine,
) ++ log4jModules), ),
libraryDependencies ++= (scalaVersion.value match { libraryDependencies ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List() case v if v.startsWith("2.12.") => List()
case _ => List(scalaPar) case _ => List(scalaPar)

View File

@ -10,11 +10,7 @@ package sbt.internal.util
import sbt.util.* import sbt.util.*
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
import org.apache.logging.log4j.core.{ LogEvent as XLogEvent }
import org.apache.logging.log4j.core.appender.AbstractAppender
import org.apache.logging.log4j.core.layout.PatternLayout
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
object BufferedAppender { object BufferedAppender {
def generateName: String = def generateName: String =
@ -36,50 +32,24 @@ object BufferedAppender {
* logged is used, not the level at the time 'play' is called. * logged is used, not the level at the time 'play' is called.
*/ */
class BufferedAppender(override val name: String, delegate: Appender) extends Appender { class BufferedAppender(override val name: String, delegate: Appender) extends Appender {
override def close(): Unit = log4j.get match { override def close(): Unit = ()
case null =>
case a => a.stop()
}
override private[sbt] def properties: ConsoleAppender.Properties = delegate.properties override private[sbt] def properties: ConsoleAppender.Properties = delegate.properties
override private[sbt] def suppressedMessage: SuppressedTraceContext => Option[String] = override private[sbt] def suppressedMessage: SuppressedTraceContext => Option[String] =
delegate.suppressedMessage delegate.suppressedMessage
private val log4j = new AtomicReference[AbstractAppender]
override private[sbt] def toLog4J = log4j.get match {
case null =>
val a = new AbstractAppender(
delegate.name + "-log4j",
null,
PatternLayout.createDefaultLayout(),
true,
Array.empty
) {
start()
override def append(event: XLogEvent): Unit = {
if (recording) {
Util.ignoreResult(buffer.add(Left(event.toImmutable)))
} else {
delegate.toLog4J.append(event)
}
}
}
log4j.set(a)
a
case a => a
}
private val buffer = private val buffer =
new java.util.Vector[Either[XLogEvent, (Level.Value, Option[String], Option[ObjectEvent[?]])]] new java.util.Vector[(Level.Value, Option[String], Option[ObjectEvent[?]])]
private var recording = false private var recording = false
override def appendLog(level: Level.Value, message: => String): Unit = { override def appendLog(level: Level.Value, message: => String): Unit = {
if (recording) Util.ignoreResult(buffer.add(Right((level, Some(message), None)))) if (recording) Util.ignoreResult(buffer.add((level, Some(message), None)))
else delegate.appendLog(level, message) else delegate.appendLog(level, message)
} }
override private[sbt] def appendObjectEvent[T]( override private[sbt] def appendObjectEvent[T](
level: Level.Value, level: Level.Value,
message: => ObjectEvent[T] message: => ObjectEvent[T]
): Unit = { ): Unit = {
if (recording) Util.ignoreResult(buffer.add(Right(((level, None, Some(message)))))) if (recording) Util.ignoreResult(buffer.add(((level, None, Some(message)))))
else delegate.appendObjectEvent(level, message) else delegate.appendObjectEvent(level, message)
} }
@ -113,12 +83,10 @@ class BufferedAppender(override val name: String, delegate: Appender) extends Ap
*/ */
def play(): Unit = def play(): Unit =
synchronized { synchronized {
buffer.forEach { buffer.forEach:
case Right((l, Some(m), _)) => delegate.appendLog(l, m) case (l, Some(m), _) => delegate.appendLog(l, m)
case Right((l, _, Some(oe))) => delegate.appendObjectEvent(l, oe) case (l, _, Some(oe)) => delegate.appendObjectEvent(l, oe)
case Left(x) => delegate.toLog4J.append(x) case _ =>
case _ =>
}
buffer.clear() buffer.clear()
} }

View File

@ -10,18 +10,10 @@ package sbt.internal.util
import java.io.{ PrintStream, PrintWriter } import java.io.{ PrintStream, PrintWriter }
import java.lang.StringBuilder import java.lang.StringBuilder
import java.nio.channels.ClosedChannelException
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger } import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
import org.apache.logging.log4j.core.appender.AbstractAppender
import org.apache.logging.log4j.core.{ Appender as XAppender, LogEvent as XLogEvent }
import org.apache.logging.log4j.message.{ Message, ObjectMessage, ReusableObjectMessage }
import org.apache.logging.log4j.{ Level as XLevel }
import sbt.internal.util.ConsoleAppender.* import sbt.internal.util.ConsoleAppender.*
import sbt.util.* import sbt.util.*
import org.apache.logging.log4j.core.AbstractLogEvent
import org.apache.logging.log4j.message.SimpleMessageFactory
import java.util.concurrent.atomic.AtomicReference
object ConsoleLogger { object ConsoleLogger {
@ -325,41 +317,6 @@ object ConsoleAppender {
) )
} }
/**
* Converts the Log4J `level` to the corresponding sbt level.
*
* @param level
* A level, as represented by Log4J.
* @return
* The corresponding level in sbt's world.
*/
def toLevel(level: XLevel): Level.Value =
level match {
case XLevel.OFF => Level.Debug
case XLevel.FATAL => Level.Error
case XLevel.ERROR => Level.Error
case XLevel.WARN => Level.Warn
case XLevel.INFO => Level.Info
case XLevel.DEBUG => Level.Debug
case _ => Level.Debug
}
/**
* Converts the sbt `level` to the corresponding Log4J level.
*
* @param level
* A level, as represented by sbt.
* @return
* The corresponding level in Log4J's world.
*/
def toXLevel(level: Level.Value): XLevel =
level match {
case Level.Error => XLevel.ERROR
case Level.Warn => XLevel.WARN
case Level.Info => XLevel.INFO
case Level.Debug => XLevel.DEBUG
}
private[sbt] def generateName(): String = "out-" + generateId.incrementAndGet private[sbt] def generateName(): String = "out-" + generateId.incrementAndGet
} }
@ -378,33 +335,7 @@ class ConsoleAppender(
override private[sbt] val properties: Properties, override private[sbt] val properties: Properties,
override private[sbt] val suppressedMessage: SuppressedTraceContext => Option[String] override private[sbt] val suppressedMessage: SuppressedTraceContext => Option[String]
) extends Appender { ) extends Appender {
private val log4j = new AtomicReference[XAppender](null) override def close(): Unit = ()
override private[sbt] lazy val toLog4J = log4j.get match {
case null =>
log4j.synchronized {
log4j.get match {
case null =>
val l = new Log4JConsoleAppender(
name,
properties,
suppressedMessage,
{ event =>
val level = ConsoleAppender.toLevel(event.getLevel)
val message = event.getMessage
try appendMessage(level, message)
catch { case _: ClosedChannelException => }
}
)
log4j.set(l)
l
case l => l
}
}
}
override def close(): Unit = log4j.get match {
case null =>
case a => a.stop()
}
} }
trait Appender extends AutoCloseable { trait Appender extends AutoCloseable {
private[sbt] def name: String private[sbt] def name: String
@ -431,8 +362,6 @@ trait Appender extends AutoCloseable {
*/ */
def getTrace: Int = synchronized { traceEnabledVar } def getTrace: Int = synchronized { traceEnabledVar }
private[sbt] def toLog4J: XAppender
/** /**
* Logs the stack trace of `t`, possibly shortening it. * Logs the stack trace of `t`, possibly shortening it.
* *
@ -557,13 +486,6 @@ trait Appender extends AutoCloseable {
out.println(toWrite) out.println(toWrite)
} }
private[util] def appendMessage(level: Level.Value, msg: Message): Unit =
msg match {
case o: ObjectMessage => appendMessageContent(level, o.getParameter)
case o: ReusableObjectMessage => appendMessageContent(level, o.getParameter)
case _ => appendLog(level, msg.getFormattedMessage)
}
private def appendTraceEvent(te: TraceEvent): Unit = { private def appendTraceEvent(te: TraceEvent): Unit = {
val traceLevel = getTrace val traceLevel = getTrace
if (traceLevel >= 0) { if (traceLevel >= 0) {
@ -616,35 +538,5 @@ trait Appender extends AutoCloseable {
appendMessageContent(level, message) appendMessageContent(level, message)
} }
private[internal] class Log4JConsoleAppender(
override private[sbt] val name: String,
override private[sbt] val properties: Properties,
override private[sbt] val suppressedMessage: SuppressedTraceContext => Option[String],
appendEvent: XLogEvent => Unit,
) extends AbstractAppender(name, null, LogExchange.dummyLayout, true, Array.empty)
with Appender {
start()
override def close(): Unit = stop()
override private[sbt] def toLog4J: XAppender = this
override def append(event: XLogEvent): Unit = appendEvent(event)
}
private[sbt] class ConsoleAppenderFromLog4J(
override private[sbt] val name: String,
override private[sbt] val properties: Properties,
override private[sbt] val suppressedMessage: SuppressedTraceContext => Option[String],
val delegate: XAppender,
) extends Appender {
def this(name: String, delegate: XAppender) =
this(name, Properties.from(Terminal.get), _ => None, delegate)
override def close(): Unit = delegate.stop()
private[sbt] def toLog4J: XAppender = delegate
override def appendLog(level: sbt.util.Level.Value, message: => String): Unit = {
delegate.append(new AbstractLogEvent {
override def getLevel(): XLevel = ConsoleAppender.toXLevel(level)
override def getMessage(): Message =
SimpleMessageFactory.INSTANCE.newMessage(message.toString, Array.empty[AnyRef])
})
}
}
final class SuppressedTraceContext(val traceLevel: Int, val useFormat: Boolean) final class SuppressedTraceContext(val traceLevel: Int, val useFormat: Boolean)

View File

@ -8,27 +8,13 @@
package sbt.util package sbt.util
import org.apache.logging.log4j.core.config.LoggerConfig import sbt.internal.util.{ Appender, ManagedLogger, TraceEvent, SuccessEvent }
import org.apache.logging.log4j.core.layout.PatternLayout
import org.apache.logging.log4j.core.{ LoggerContext as XLoggerContext }
import org.apache.logging.log4j.{ LogManager as XLogManager }
import sbt.internal.util.{ Appender, ManagedLogger, TraceEvent, SuccessEvent, Util }
import sbt.internal.util.appmacro.StringTypeTag import sbt.internal.util.appmacro.StringTypeTag
import java.util.concurrent.ConcurrentHashMap
import scala.collection.concurrent import scala.collection.concurrent
// http://logging.apache.org/log4j/2.x/manual/customconfig.html
// https://logging.apache.org/log4j/2.x/log4j-core/apidocs/index.html
sealed abstract class LogExchange { sealed abstract class LogExchange {
private[sbt] lazy val context: XLoggerContext = init()
private[sbt] val stringCodecs: concurrent.Map[String, ShowLines[?]] = concurrent.TrieMap() private[sbt] val stringCodecs: concurrent.Map[String, ShowLines[?]] = concurrent.TrieMap()
private[sbt] val builtInStringCodecs: Unit = initStringCodecs() private[sbt] val builtInStringCodecs: Unit = initStringCodecs()
private[util] val configs = new ConcurrentHashMap[String, LoggerConfig]
private[util] def addConfig(name: String, config: LoggerConfig): Unit =
Util.ignoreResult(configs.putIfAbsent(name, config))
private[util] def removeConfig(name: String): Option[LoggerConfig] = Option(configs.remove(name))
def logger(name: String): ManagedLogger = logger(name, None, None) def logger(name: String): ManagedLogger = logger(name, None, None)
def logger(name: String, channelName: Option[String], execId: Option[String]): ManagedLogger = def logger(name: String, channelName: Option[String], execId: Option[String]): ManagedLogger =
@ -55,21 +41,6 @@ sealed abstract class LogExchange {
registerStringCodec[SuccessEvent] registerStringCodec[SuccessEvent]
} }
// This is a dummy layout to avoid casting error during PatternLayout.createDefaultLayout()
// that was originally used for ConsoleAppender.
// The stacktrace shows it's having issue initializing default DefaultConfiguration.
// Since we currently do not use Layout inside ConsoleAppender, the actual pattern is not relevant.
private[sbt] lazy val dummyLayout: PatternLayout = {
val _ = context
val ctx = XLogManager.getContext(false) match { case x: XLoggerContext => x }
val config = ctx.getConfiguration
val lo = PatternLayout.newBuilder
.withConfiguration(config)
.withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN)
.build
lo
}
def stringCodec[A](tag: String): Option[ShowLines[A]] = def stringCodec[A](tag: String): Option[ShowLines[A]] =
stringCodecs.get(tag) map { _.asInstanceOf[ShowLines[A]] } stringCodecs.get(tag) map { _.asInstanceOf[ShowLines[A]] }
def hasStringCodec(tag: String): Boolean = def hasStringCodec(tag: String): Boolean =
@ -82,15 +53,5 @@ sealed abstract class LogExchange {
val tag = implicitly[StringTypeTag[A]] val tag = implicitly[StringTypeTag[A]]
val _ = getOrElseUpdateStringCodec(tag.key, ev) val _ = getOrElseUpdateStringCodec(tag.key, ev)
} }
private[sbt] def init(): XLoggerContext = {
import org.apache.logging.log4j.core.config.Configurator
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory
val builder = ConfigurationBuilderFactory.newConfigurationBuilder
builder.setConfigurationName("sbt.util.logging")
val ctx = Configurator.initialize(builder.build())
ctx match { case x: XLoggerContext => x }
}
private[sbt] def init(name: String): XLoggerContext = new XLoggerContext(name)
} }
object LogExchange extends LogExchange object LogExchange extends LogExchange

View File

@ -16,7 +16,6 @@ import lmcoursier.CoursierDependencyResolution
import lmcoursier.definitions.{ Configuration as CConfiguration } import lmcoursier.definitions.{ Configuration as CConfiguration }
import org.apache.ivy.core.module.descriptor.ModuleDescriptor import org.apache.ivy.core.module.descriptor.ModuleDescriptor
import org.apache.ivy.core.module.id.ModuleRevisionId import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.logging.log4j.core.{ Appender as XAppender }
import org.scalasbt.ipcsocket.Win32SecurityLevel import org.scalasbt.ipcsocket.Win32SecurityLevel
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition, parsed } import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition, parsed }
import sbt.Keys.* import sbt.Keys.*
@ -332,19 +331,11 @@ object Defaults extends BuildCommon {
try onUnload.value(s) try onUnload.value(s)
finally IO.delete(taskTemporaryDirectory.value) finally IO.delete(taskTemporaryDirectory.value)
}, },
// // extraLoggers is deprecated extraAppenders :== {
SettingKey[ScopedKey[?] => Seq[XAppender]]("extraLoggers") :== { _ => new AppenderSupplier:
Nil def apply(s: ScopedKey[?]): Seq[Appender] = Nil
}, },
extraAppenders := { useLog4J :== false,
val f = SettingKey[ScopedKey[?] => Seq[XAppender]]("extraLoggers").value
s =>
f(s).map {
case a: Appender => a
case a => new ConsoleAppenderFromLog4J(a.getName, a)
}
},
useLog4J :== SysProp.useLog4J,
watchSources :== Nil, // Although this is deprecated, it can't be removed or it breaks += for legacy builds. watchSources :== Nil, // Although this is deprecated, it can't be removed or it breaks += for legacy builds.
skip :== false, skip :== false,
taskTemporaryDirectory := { taskTemporaryDirectory := {

View File

@ -15,7 +15,6 @@ import lmcoursier.definitions.{ CacheLogger, ModuleMatchers, Reconciliation }
import lmcoursier.{ CoursierConfiguration, FallbackDependency } import lmcoursier.{ CoursierConfiguration, FallbackDependency }
import org.apache.ivy.core.module.descriptor.ModuleDescriptor import org.apache.ivy.core.module.descriptor.ModuleDescriptor
import org.apache.ivy.core.module.id.ModuleRevisionId import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.logging.log4j.core.{ Appender as XAppender }
import sbt.Def.* import sbt.Def.*
import sbt.KeyRanks.* import sbt.KeyRanks.*
import sbt.internal.InMemoryCacheStore.CacheStoreFactoryFactory import sbt.internal.InMemoryCacheStore.CacheStoreFactoryFactory
@ -62,8 +61,7 @@ object Keys {
val showSuccess = settingKey[Boolean]("If true, displays a success message after running a command successfully.").withRank(CSetting) val showSuccess = settingKey[Boolean]("If true, displays a success message after running a command successfully.").withRank(CSetting)
val showTiming = settingKey[Boolean]("If true, the command success message includes the completion time.").withRank(CSetting) val showTiming = settingKey[Boolean]("If true, the command success message includes the completion time.").withRank(CSetting)
val timingFormat = settingKey[java.text.DateFormat]("The format used for displaying the completion time.").withRank(CSetting) val timingFormat = settingKey[java.text.DateFormat]("The format used for displaying the completion time.").withRank(CSetting)
@deprecated("", "1.4.0") @transient
val extraLoggers = settingKey[ScopedKey[?] => Seq[XAppender]]("A function that provides additional loggers for a given setting.").withRank(DSetting)
val extraAppenders = settingKey[AppenderSupplier]("A function that provides additional loggers for a given setting.").withRank(DSetting) val extraAppenders = settingKey[AppenderSupplier]("A function that provides additional loggers for a given setting.").withRank(DSetting)
val useLog4J = settingKey[Boolean]("Toggles whether or not to use log4j for sbt internal loggers.").withRank(Invisible) val useLog4J = settingKey[Boolean]("Toggles whether or not to use log4j for sbt internal loggers.").withRank(Invisible)
val logManager = settingKey[LogManager]("The log manager, which creates Loggers for different contexts.").withRank(DSetting) val logManager = settingKey[LogManager]("The log manager, which creates Loggers for different contexts.").withRank(DSetting)

View File

@ -28,9 +28,6 @@ import sbt.nio.file.{ Glob, RecursiveGlob }
object ScriptedPlugin extends AutoPlugin { object ScriptedPlugin extends AutoPlugin {
// Force Log4J to not use a thread context classloader otherwise it throws a CCE
sys.props(org.apache.logging.log4j.util.LoaderUtil.IGNORE_TCCL_PROPERTY) = "true"
object autoImport { object autoImport {
val ScriptedConf = Configurations.config("scripted-sbt").hide val ScriptedConf = Configurations.config("scripted-sbt").hide
val ScriptedLaunchConf = Configurations.config("scripted-sbt-launch").hide val ScriptedLaunchConf = Configurations.config("scripted-sbt-launch").hide

View File

@ -42,9 +42,6 @@ lazy val root = (project in file("."))
"net.java.dev.jna:jna", "net.java.dev.jna:jna",
"net.java.dev.jna:jna-platform", "net.java.dev.jna:jna-platform",
"net.openhft:zero-allocation-hashing", "net.openhft:zero-allocation-hashing",
"org.apache.logging.log4j:log4j-api",
"org.apache.logging.log4j:log4j-core",
"org.apache.logging.log4j:log4j-slf4j-impl",
"org.checkerframework:checker-qual", "org.checkerframework:checker-qual",
"org.fusesource.jansi:jansi", "org.fusesource.jansi:jansi",
"org.jline:jline-builtins", "org.jline:jline-builtins",