mirror of https://github.com/sbt/sbt.git
[2.x] fix: sbt -debug doesn't display loading log (#8819)
* Fix #4979: apply -debug (and other level options) at startup so loading shows debug log - Parse log level from configuration.arguments in StandardMain.initialState - Pass initialLevel to GlobalLogging.initial so console appender uses it from first log - Set Keys.logLevel and BasicKeys.explicitGlobalLogLevels in initial state when level option present - Add initialLevel parameter to GlobalLogging.initial (default Level.Info) for backward compatibility - Add InitialLogLevelSpec tests for logLevelFromArguments - Add docs/fix-4979-manual-verification.md for manual reproduction
This commit is contained in:
parent
f04093bd9f
commit
33ac10c1ce
|
|
@ -84,11 +84,19 @@ object GlobalLogging {
|
|||
newAppender: (ManagedLogger, PrintWriter, GlobalLogBacking, LoggerContext) => GlobalLogging,
|
||||
newBackingFile: => File,
|
||||
console: ConsoleOut
|
||||
): GlobalLogging =
|
||||
initial(newAppender, newBackingFile, console, Level.Info)
|
||||
|
||||
def initial(
|
||||
newAppender: (ManagedLogger, PrintWriter, GlobalLogBacking, LoggerContext) => GlobalLogging,
|
||||
newBackingFile: => File,
|
||||
console: ConsoleOut,
|
||||
initialLevel: Level.Value = Level.Info
|
||||
): GlobalLogging = {
|
||||
val loggerName = generateName
|
||||
val log = LoggerContext.globalContext.logger(loggerName, None, None)
|
||||
val appender = ConsoleAppender(ConsoleAppender.generateName(), console)
|
||||
LoggerContext.globalContext.addAppender(loggerName, appender -> Level.Info)
|
||||
LoggerContext.globalContext.addAppender(loggerName, appender -> initialLevel)
|
||||
GlobalLogging(log, console, appender, GlobalLogBacking(newBackingFile), newAppender)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,17 +246,33 @@ object StandardMain {
|
|||
ConsoleOut.systemOutOverwrite(ConsoleOut.overwriteContaining("Resolving "))
|
||||
ConsoleOut.setGlobalProxy(console)
|
||||
|
||||
private def initialGlobalLogging(file: Option[File]): GlobalLogging = {
|
||||
def createTemp(attempt: Int = 0): File = Retry {
|
||||
private[sbt] def logLevelFromArguments(args: Seq[String]): Level.Value =
|
||||
val earlyCmd = BasicCommandStrings.EarlyCommand
|
||||
val levelOptions = Level.values.toSeq.flatMap: v =>
|
||||
List("-" + v.toString, "--" + v.toString)
|
||||
def levelFromArg(arg: String): Option[Level.Value] =
|
||||
if arg.startsWith(earlyCmd + "(") && arg.endsWith(")") then
|
||||
val inner = arg.slice(earlyCmd.length + 1, arg.length - 1).trim
|
||||
Level.values.find(_.toString == inner)
|
||||
else if levelOptions.contains(arg) then
|
||||
Level.values.find(v => arg == "-" + v.toString || arg == "--" + v.toString)
|
||||
else None
|
||||
args.flatMap(levelFromArg).headOption.getOrElse(Level.Info)
|
||||
|
||||
private def initialGlobalLogging(file: Option[File], initialLevel: Level.Value): GlobalLogging =
|
||||
def createTemp(attempt: Int = 0): File = Retry:
|
||||
file.foreach(f => if (!f.exists()) IO.createDirectory(f))
|
||||
File.createTempFile("sbt-global-log", ".log", file.orNull)
|
||||
}
|
||||
GlobalLogging.initial(
|
||||
MainAppender.globalDefault(ConsoleOut.globalProxy),
|
||||
createTemp(),
|
||||
ConsoleOut.globalProxy
|
||||
ConsoleOut.globalProxy,
|
||||
initialLevel
|
||||
)
|
||||
}
|
||||
|
||||
private def initialGlobalLogging(file: Option[File]): GlobalLogging =
|
||||
initialGlobalLogging(file, Level.Info)
|
||||
|
||||
def initialGlobalLogging(file: File): GlobalLogging = initialGlobalLogging(Option(file))
|
||||
@deprecated("use version that takes file argument", "1.4.0")
|
||||
def initialGlobalLogging: GlobalLogging = initialGlobalLogging(None)
|
||||
|
|
@ -265,8 +281,7 @@ object StandardMain {
|
|||
configuration: xsbti.AppConfiguration,
|
||||
initialDefinitions: Seq[Command],
|
||||
preCommands: Seq[String]
|
||||
): State = {
|
||||
// This is to workaround https://github.com/sbt/io/issues/110
|
||||
): State =
|
||||
if (!sys.props.contains("jna.nosys")) sys.props.put("jna.nosys", "true")
|
||||
|
||||
import BasicCommandStrings.{ DashDashDetachStdio, DashDashServer, isEarlyCommand }
|
||||
|
|
@ -274,11 +289,18 @@ object StandardMain {
|
|||
configuration.arguments
|
||||
.map(_.trim)
|
||||
.filterNot(c => c == DashDashDetachStdio || c == DashDashServer)
|
||||
.toSeq
|
||||
val initialLevel = logLevelFromArguments(userCommands)
|
||||
val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand)
|
||||
val commands = (earlyCommands ++ normalCommands).toList map { x =>
|
||||
Exec(x, None)
|
||||
}
|
||||
val initAttrs = BuiltinCommands.initialAttributes
|
||||
val commands = (earlyCommands ++ normalCommands).toList.map(x => Exec(x, None))
|
||||
val baseAttrs = BuiltinCommands.initialAttributes
|
||||
val initAttrs =
|
||||
if initialLevel == Level.Info then baseAttrs
|
||||
else
|
||||
baseAttrs
|
||||
.put(Keys.logLevel.key, initialLevel)
|
||||
.put(BasicKeys.explicitGlobalLogLevels, true)
|
||||
val logDir = BuildPaths.globalLoggingStandard(configuration.baseDirectory)
|
||||
val s = State(
|
||||
configuration,
|
||||
initialDefinitions,
|
||||
|
|
@ -287,12 +309,12 @@ object StandardMain {
|
|||
commands,
|
||||
State.newHistory,
|
||||
initAttrs,
|
||||
initialGlobalLogging(BuildPaths.globalLoggingStandard(configuration.baseDirectory)),
|
||||
initialGlobalLogging(Option(logDir), initialLevel),
|
||||
None,
|
||||
State.Continue
|
||||
)
|
||||
s.initializeClassLoaderCache
|
||||
}
|
||||
end initialState
|
||||
}
|
||||
|
||||
import sbt.BasicCommandStrings.*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2023, Scala center
|
||||
* Copyright 2011 - 2022, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package internal
|
||||
|
||||
import sbt.util.Level
|
||||
|
||||
object InitialLogLevelSpec extends verify.BasicTestSuite:
|
||||
|
||||
test("logLevelFromArguments returns Debug when -debug is in arguments"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq("-debug")) == Level.Debug)
|
||||
|
||||
test("logLevelFromArguments returns Debug when --debug is in arguments"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq("compile", "--debug")) == Level.Debug)
|
||||
|
||||
test("logLevelFromArguments returns Debug when early(debug) is in arguments"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq("early(debug)")) == Level.Debug)
|
||||
assert(StandardMain.logLevelFromArguments(Seq("compile", "early(debug)")) == Level.Debug)
|
||||
|
||||
test("logLevelFromArguments returns Info when no level option in arguments"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq()) == Level.Info)
|
||||
assert(StandardMain.logLevelFromArguments(Seq("compile", "run")) == Level.Info)
|
||||
|
||||
test("logLevelFromArguments uses first level option when multiple present"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq("-warn", "-debug")) == Level.Warn)
|
||||
assert(StandardMain.logLevelFromArguments(Seq("-error", "-info")) == Level.Error)
|
||||
|
||||
test("logLevelFromArguments supports all level options"):
|
||||
assert(StandardMain.logLevelFromArguments(Seq("-info")) == Level.Info)
|
||||
assert(StandardMain.logLevelFromArguments(Seq("--warn")) == Level.Warn)
|
||||
assert(StandardMain.logLevelFromArguments(Seq("--error")) == Level.Error)
|
||||
end InitialLogLevelSpec
|
||||
Loading…
Reference in New Issue