Skip to content

Commit

Permalink
Cleanup logger (#4653)
Browse files Browse the repository at this point in the history
A step towards #3603. For now
just doing relatively shallow cleanups, but hopefully that paves the way
to bigger refactorings


The main external-facing change is renaming
`inStream`/`outputStream`/`errorStream` to `streams.in`/`out`/`err`,
though the internal refactorings are more substantial
  • Loading branch information
lihaoyi authored Mar 5, 2025
1 parent 667e641 commit 59764e8
Show file tree
Hide file tree
Showing 32 changed files with 416 additions and 464 deletions.
4 changes: 2 additions & 2 deletions bsp/src/mill/bsp/BSP.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ object BSP extends ExternalModule with CoursierModule {
*/
def startSession(allBootstrapEvaluators: Evaluator.AllBootstrapEvaluators)
: Command[BspServerResult] = Task.Command(exclusive = true) {
Task.log.errorStream.println("BSP/startSession: Starting BSP session")
Task.log.streams.err.println("BSP/startSession: Starting BSP session")
val res = BspContext.bspServerHandle.runSession(allBootstrapEvaluators.value)
Task.log.errorStream.println(s"BSP/startSession: Finished BSP session, result: ${res}")
Task.log.streams.err.println(s"BSP/startSession: Finished BSP session, result: ${res}")
res
}

Expand Down
19 changes: 9 additions & 10 deletions bsp/src/mill/bsp/BspContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private[mill] class BspContext(
BspContext.bspServerHandle =
try {
startBspServer(
streams = streams,
streams0 = streams,
logStream = bspLogStream,
canReload = true
).get
Expand All @@ -37,27 +37,26 @@ private[mill] class BspContext(
streams.err.println("BSP server started")

def startBspServer(
streams: SystemStreams,
streams0: SystemStreams,
logStream: Option[PrintStream],
canReload: Boolean
): Result[BspServerHandle] = {
val log: Logger = new Logger {
override def colored: Boolean = false
override def systemStreams: SystemStreams = new SystemStreams(
out = streams.out,
err = streams.err,
override def streams: SystemStreams = new SystemStreams(
out = streams0.out,
err = streams0.err,
in = DummyInputStream
)
def prompt = new Logger.Prompt.NoOp {
override def setPromptDetail(key: Seq[String], s: String): Unit = streams.err.println(s)
}

override def info(s: String): Unit = streams.err.println(s)
override def error(s: String): Unit = streams.err.println(s)
override def ticker(s: String): Unit = streams.err.println(s)
override def setPromptDetail(key: Seq[String], s: String): Unit = streams.err.println(s)
override def debug(s: String): Unit = streams.err.println(s)

override def debugEnabled: Boolean = true

override def rawOutputStream: PrintStream = systemStreams.out
override def debug(s: String): Unit = streams.err.println(s)
}

BspWorker(mill.api.WorkspaceRoot.workspaceRoot, home, log).flatMap { worker =>
Expand Down
4 changes: 2 additions & 2 deletions bsp/worker/src/mill/bsp/worker/MillBspLogger.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package mill.bsp.worker

import ch.epfl.scala.bsp4j._
import mill.api.{ColorLogger, Logger}
import mill.api.{Logger}
import mill.internal.ProxyLogger

/**
Expand All @@ -19,7 +19,7 @@ import mill.internal.ProxyLogger
*/
private class MillBspLogger(client: BuildClient, taskId: Int, logger: Logger)
extends ProxyLogger(logger)
with ColorLogger {
with Logger {
override def infoColor = fansi.Color.Blue
override def errorColor = fansi.Color.Red

Expand Down
6 changes: 3 additions & 3 deletions bsp/worker/src/mill/bsp/worker/MillBuildServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ch.epfl.scala.bsp4j
import ch.epfl.scala.bsp4j.*
import com.google.gson.JsonObject
import mill.api.ExecResult
import mill.api.{ColorLogger, CompileProblemReporter, DummyTestReporter, Result, TestReporter}
import mill.api.{Logger, CompileProblemReporter, DummyTestReporter, Result, TestReporter}
import mill.bsp.{BspServerResult, Constants}
import mill.bsp.worker.Utils.{makeBuildTarget, outputPaths, sanitizeUri}
import mill.define.Segment.Label
Expand Down Expand Up @@ -801,7 +801,7 @@ private class MillBuildServer(
goals: Seq[Task[?]],
reporter: Int => Option[CompileProblemReporter] = _ => Option.empty[CompileProblemReporter],
testReporter: TestReporter = DummyTestReporter,
logger: ColorLogger = null
logger: Logger = null
): ExecutionResults = {
val logger0 = Option(logger).getOrElse(evaluator.baseLogger)
mill.runner.MillMain.withOutLock(
Expand All @@ -812,7 +812,7 @@ private class MillBuildServer(
case n: NamedTask[_] => n.label
case t => t.toString
},
streams = logger0.systemStreams
streams = logger0.streams
) {
evaluator.execute(
goals,
Expand Down
64 changes: 61 additions & 3 deletions ci/mill-bootstrap.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/build.mill b/build.mill
index 5c48e1e4e43..538e4b86e0c 100644
index 42be8622781..ecb84c31089 100644
--- a/build.mill
+++ b/build.mill
@@ -1,16 +1,16 @@
Expand Down Expand Up @@ -189,7 +189,7 @@ index e49f218f4be..9d03aa073f3 100644
def ivyDeps = Task {
if (!caseName.contains("realistic") && !caseName.contains("sourcecode")) super.ivyDeps()
diff --git a/dist/package.mill b/dist/package.mill
index fbbeacbc843..fb06c486273 100644
index fbbeacbc843..b3e00f8db5f 100644
--- a/dist/package.mill
+++ b/dist/package.mill
@@ -2,15 +2,14 @@ package build.dist
Expand All @@ -210,6 +210,15 @@ index fbbeacbc843..fb06c486273 100644
case m: PublishModule if (m ne build.dist) && (m ne build.dist.native) => m
}
def moduleDeps = Seq(build.runner, build.idea, build.main.init)
@@ -44,7 +43,7 @@ trait InstallModule extends build.MillPublishJavaModule {
(os.home / ".cache/mill/download" / (build.millVersion() + batExt)).toString()
)
)()
- Task.log.outputStream.println(path.toString())
+ Task.log.streams.out.println(path.toString())
PathRef(path)
}

@@ -185,10 +184,10 @@ object `package` extends RootModule with InstallModule {
val wd = os.Path(wd0, Task.workspace)
os.makeDir.all(wd)
Expand Down Expand Up @@ -650,7 +659,7 @@ index 3b577e29c65..7f45dcaeab6 100644
def forkEnv =
super.forkEnv() ++ Map("MILL_EXECUTABLE_PATH" -> build.dist.launcher().path.toString())
diff --git a/website/package.mill b/website/package.mill
index f88dc3fe8f6..eb1916dae76 100644
index f88dc3fe8f6..2e2d2be3716 100644
--- a/website/package.mill
+++ b/website/package.mill
@@ -26,7 +26,7 @@ object `package` extends RootModule {
Expand Down Expand Up @@ -753,3 +762,52 @@ index f88dc3fe8f6..eb1916dae76 100644
def blogFolder = Task {
os.copy(blogFolder0().path, Task.dest, mergeFolders = true)
expandDiagramsInDirectoryAdocFile(Task.dest, mill.main.VisualizeModule.classpath().map(_.path))
@@ -332,21 +332,21 @@ object `package` extends RootModule {

def localPages: T[PathRef] = Task {
val pages = generatePages(authorMode = true).apply().apply(oldDocSources().map(_.path))
- Task.log.outputStream.println(
+ Task.log.streams.out.println(
s"You can browse the pages at: ${(pages.path / "index.html").toNIO.toUri()}"
)
pages
}
def fastPages: T[PathRef] = Task {
val pages = generatePages(authorMode = true).apply().apply(Nil)
- Task.log.outputStream.println(
+ Task.log.streams.out.println(
s"You can browse the pages at: ${(pages.path / "index.html").toNIO.toUri()}"
)
pages
}

def generatePages(authorMode: Boolean) = Task.Anon { (extraSources: Seq[os.Path]) =>
- Task.log.errorStream.println("Creating Antora playbook ...")
+ Task.log.streams.err.println("Creating Antora playbook ...")
// dependency to sources
source()
val docSite = Task.dest
@@ -357,7 +357,7 @@ object `package` extends RootModule {
data = githubPagesPlaybookText(authorMode).apply().apply(extraSources),
createFolders = true
)
- Task.log.errorStream.println("Running Antora ...")
+ Task.log.streams.err.println("Running Antora ...")
runAntora(
npmDir = npmBase(),
workDir = docSite,
@@ -373,12 +373,12 @@ object `package` extends RootModule {
os.write(siteDir / ".nojekyll", "")

// sanitize devAntora source URLs
- Task.log.errorStream.println("Sanitizing links ...")
+ Task.log.streams.err.println("Sanitizing links ...")
sanitizeDevUrls(siteDir, devAntoraSources().path, build.baseDir / "docs", build.baseDir)

// only copy the "api" sub-dir; api docs contains a top-level index.html with we don't want
val unidocSrc = if (authorMode) site.unidocLocal().path else site.unidocSite().path
- Task.log.errorStream.println(s"Copying API docs from ${unidocSrc} ...")
+ Task.log.streams.err.println(s"Copying API docs from ${unidocSrc} ...")
os.copy(unidocSrc, siteDir / "api/latest", createFolders = true)

PathRef(siteDir)
2 changes: 1 addition & 1 deletion contrib/flyway/src/mill/contrib/flyway/FlywayModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ trait FlywayModule extends JavaModule {
val out =
s"""Schema version: ${currentSchemaVersion}
|${MigrationInfoDumper.dumpToAsciiTable(info.all)}""".stripMargin
Task.log.outputStream.println(out)
Task.log.streams.out.println(out)
out
}
}
Expand Down
7 changes: 0 additions & 7 deletions core/api/src/mill/api/ColorLogger.scala

This file was deleted.

97 changes: 52 additions & 45 deletions core/api/src/mill/api/Logger.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package mill.api

import java.io.{InputStream, PrintStream}
import java.io.PrintStream

/**
* The standard logging interface of the Mill build tool.
Expand All @@ -24,66 +24,73 @@ import java.io.{InputStream, PrintStream}
* but when `show` is used both are forwarded to stderr and stdout is only
* used to display the final `show` output for easy piping.
*/
trait Logger extends AutoCloseable {
trait Logger {
def infoColor: fansi.Attrs = fansi.Attrs.Empty
def errorColor: fansi.Attrs = fansi.Attrs.Empty
def colored: Boolean

private[mill] def unprefixedSystemStreams: SystemStreams = systemStreams
def systemStreams: SystemStreams

def errorStream: PrintStream = systemStreams.err
def outputStream: PrintStream = systemStreams.out

/**
* [[rawOutputStream]] is intended to be a version of [[outputStream]]
* without decoration: colors, prefixes, timestamps, etc. It is intended
* for the use of tasks like `show` which output data in a way that is
* easily readable by downstream programs.
*/
def rawOutputStream: PrintStream = systemStreams.out
def inStream: InputStream = systemStreams.in
private[mill] def unprefixedStreams: SystemStreams = streams
def streams: SystemStreams

def info(s: String): Unit
def debug(s: String): Unit
def error(s: String): Unit
def ticker(s: String): Unit

private[mill] def setPromptDetail(key: Seq[String], s: String): Unit = ticker(s)
private[mill] def reportKey(key: Seq[String]): Unit = ()
private[mill] def setPromptLine(
key: Seq[String],
verboseKeySuffix: String,
message: String
): Unit =
ticker(s"${key.mkString("-")} $message")
private[mill] def setPromptLine(): Unit = ()
private[mill] def setPromptHeaderPrefix(s: String): Unit = ()
private[mill] def clearPromptStatuses(): Unit = ()
private[mill] def removePromptLine(key: Seq[String]): Unit = ()
private[mill] def removePromptLine(): Unit = ()
private[mill] def withPromptPaused[T](t: => T): T = t
private[mill] def withPromptUnpaused[T](t: => T): T = t

/**
* @since Mill 0.10.5
*/
// We only default-implement it to keep binary compatibility in 0.10.x
def debugEnabled: Boolean = false

def close(): Unit = ()
private[mill] def prompt: Logger.Prompt

def enableTicker: Boolean = false

private[mill] def subLogger(path: os.Path, verboseKeySuffix: String, message: String): Logger =
private[mill] def subLogger(path: os.Path, keySuffix: String, message: String): Logger =
this

private[mill] def withPrompt[T](t: => T): T = {
setPromptLine()
private[mill] def withPromptLine[T](t: => T): T = {
prompt.setPromptLine(logPrefixKey, keySuffix, message)
try t
finally removePromptLine()
finally prompt.removePromptLine(logPrefixKey)
}

def withOutStream(outStream: PrintStream): Logger = this
private[mill] def message: String = ""
private[mill] def keySuffix: String = ""
private[mill] def logPrefixKey: Seq[String] = Nil
final def debugEnabled = prompt.debugEnabled
}

object Logger {

/**
* APIs that allow a logger to interact with the global prompt: setting and unsetting
* lines, enabling or disabling the prompt, etc. Normally passed through from logger
* to logger unchanged without any customization.
*/
trait Prompt {
private[mill] def setPromptDetail(key: Seq[String], s: String): Unit
private[mill] def reportKey(key: Seq[String]): Unit
private[mill] def setPromptLine(key: Seq[String], keySuffix: String, message: String): Unit
private[mill] def setPromptHeaderPrefix(s: String): Unit
private[mill] def clearPromptStatuses(): Unit
private[mill] def removePromptLine(key: Seq[String]): Unit
private[mill] def withPromptPaused[T](t: => T): T
private[mill] def withPromptUnpaused[T](t: => T): T

def debugEnabled: Boolean

def enableTicker: Boolean
}
object Prompt {
class NoOp extends Prompt {
private[mill] def setPromptDetail(key: Seq[String], s: String): Unit = ()
private[mill] def reportKey(key: Seq[String]): Unit = ()
private[mill] def setPromptLine(key: Seq[String], keySuffix: String, message: String): Unit =
()
private[mill] def setPromptHeaderPrefix(s: String): Unit = ()
private[mill] def clearPromptStatuses(): Unit = ()
private[mill] def removePromptLine(key: Seq[String]): Unit = ()
private[mill] def withPromptPaused[T](t: => T): T = t
private[mill] def withPromptUnpaused[T](t: => T): T = t

def debugEnabled: Boolean = false

def enableTicker: Boolean = false
}
}
}
6 changes: 3 additions & 3 deletions core/define/src/mill/define/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ trait Evaluator extends AutoCloseable {
private[mill] def allowPositionalCommandArgs: Boolean
private[mill] def selectiveExecution: Boolean
private[mill] def workspace: os.Path
private[mill] def baseLogger: ColorLogger
private[mill] def baseLogger: Logger
private[mill] def outPath: os.Path
private[mill] def codeSignatures: Map[String, Int]
private[mill] def rootModule: BaseModule
private[mill] def workerCache: mutable.Map[Segments, (Int, Val)]
private[mill] def env: Map[String, String]

def withBaseLogger(newBaseLogger: ColorLogger): Evaluator
def withBaseLogger(newBaseLogger: Logger): Evaluator

def resolveSegments(
scriptArgs: Seq[String],
Expand All @@ -38,7 +38,7 @@ trait Evaluator extends AutoCloseable {
targets: Seq[Task[T]],
reporter: Int => Option[CompileProblemReporter] = _ => Option.empty[CompileProblemReporter],
testReporter: TestReporter = DummyTestReporter,
logger: ColorLogger = baseLogger,
logger: Logger = baseLogger,
serialCommandExec: Boolean = false,
selectiveExecution: Boolean = false
): Evaluator.Result[T]
Expand Down
Loading

0 comments on commit 59764e8

Please sign in to comment.