sbt, the interactive build tool
Go to file
Ethan Atkins 2e9805b9d0 Add internal multi logger implementation
Prior to these changes, sbt was leaking large amounts of memory via
log4j appenders. sbt has an unusual use case for log4j because it
creates many ephemeral loggers while also having a global logger that is
supposed to work for the duration of the sbt session. There is a lot of
shared global state in log4j and properly cleaning up the ephemeral task
appenders would break global logging. This commit fixes the behavior by
introducing an alternate logging implementation. Users can still use the
old log4j logging implementation but it will be off by default. The
internal implementation is very simple: it just blocks the current
thread and writes to all of the appenders. Nevertheless, I found the
performance to be roughly identical to that of log4j in my sample
project. As an experiment, I did the appending on a thread pool and got
a significant performance improvement but I'll defer that to a later PR
since parallel io is harder to reason about.

Background: I was testing sbt performance in
https://github.com/jtjeferreira/sbt-multi-module-sample and noticed that
performance rapidly degraded after I ran compile a few times. I took a
heap dump and it became obvious that sbt was leaking console appenders.
Further investigation revealed that all of the leaking appenders in the
project were coming from task streams. This made me think that the fix
would be to track what loggers were created during task evaluation and
clear them out when task evaluation completed. That almost worked except
that log4j has an internal append only data structure containing logger
names. Since we create unique logger names for each run, that internal
data structure grew without bound. It looked like this could be worked
around by creating a new log4j Configuration (where that data structure
was stored) but while creating new configurations with each task runs
did fix the leak, it also broke global logging, which was using a
different configuration. At this point, I decided to write an alternate
implementation of the appender api where I could be sure that the
appenders were cleaned up without breaking global logging.

Implementation: I made ConsoleAppender a trait and made it no longer
extends log4j AbstractAppender. To do this, I had to remove the one
log4j specific method, append(LogEvent). ConsoleAppender now has a
method toLog4J that, in most cases, will return a log4j Appender that is
almost identical to the Appenders that we previously used. To manage
the loggers created during task evaluation, I introduce a new class,
LoggerContext. The LoggerContext determines which logging backend to use
and keeps track of what appenders and loggers have been created. We can
create a fresh LoggerContext before each task evaluation and clear it
out, cleaning up all of its resources after task evaluation concludes.

In order to make this work, there were many places where we need to
either pass in a LoggerContext or create a new one. The main magic is
happening in the `next(State)` method in Main. This is where we create a
new LoggerContext prior to command evaluation and clean it up after the
evaluation completes.

Users can toggle log4j using the new useLog4J key. They also can set the
system property, sbt.log.uselog4j. The global logger will use the sbt
internal implementation unless the system property is set.

There are a fairly significant number of mima issues since I changed the
type of ConsoleAppender. All of the mima changes were in the
sbt.internal package so I think this should be ok.

Effects: the memory leaks are gone. I successfully ran 5000 no-op
compiles in the sbt-multi-module-sample above with no degradation of
performace. There was a noticeable degradation after 30 no-op compiles
before.

During the refactor, I had to work on TestLogger and in doing so I also
fixed https://github.com/sbt/sbt/issues/4480.

This also should fix https://github.com/sbt/sbt/issues/4773
2020-08-09 11:20:34 -07:00
.github/ISSUE_TEMPLATE Update issue template 2020-02-03 14:28:20 -05:00
client Upgrade LineReader to JLine3 2020-07-10 13:37:53 -07:00
core-macros/src/main/scala/sbt/internal/util/appmacro Use a macro to create StringTypeTag instances 2020-08-08 09:02:38 -07:00
internal Add internal multi logger implementation 2020-08-09 11:20:34 -07:00
launch Adds sbt.boot.lock sysprop to opt-out 2018-02-08 13:02:39 +00:00
licenses move remaining pieces of sbt subproject to sbt_pending and fix notices 2010-09-21 21:55:50 -04:00
main Add internal multi logger implementation 2020-08-09 11:20:34 -07:00
main-actions/src Build pipelining 2020-08-06 02:31:01 -04:00
main-command/src Remove SetTerminal command 2020-08-08 09:48:48 -07:00
main-settings/src Build pipelining 2020-08-06 02:31:01 -04:00
notes Merge pull request #5041 from jsoref/https 2020-06-14 17:34:58 -04:00
project Use java caffeine library rather than scalacache 2020-08-07 17:18:09 -07:00
protocol/src/main Support System.err in thin client 2020-07-21 13:27:32 -07:00
run Add loop to SelectMainClass 2020-07-10 13:37:54 -07:00
sbt/src Add internal multi logger implementation 2020-08-09 11:20:34 -07:00
scripted-plugin/src/main/scala/sbt -Xfatal-warnings in most subprojects 2018-09-18 11:47:55 -04:00
scripted-sbt-old/src/main/scala/sbt/test Update header 2018-09-14 04:53:36 -04:00
scripted-sbt-redux Stop instrumenting scripted 2020-07-31 18:56:04 -07:00
server-test/src Build pipelining 2020-08-06 02:31:01 -04:00
src/main/conscript sbt 1.3.0 2019-09-04 01:24:08 -04:00
tasks Name threads in completion service 2020-06-22 13:14:55 -07:00
tasks-standard Selective functor 2020-05-17 23:36:04 -04:00
testing Add internal multi logger implementation 2020-08-09 11:20:34 -07:00
util-cache Don't use last modified time of directories in doc 2020-01-13 13:11:09 -08:00
util-tracking update scaladoc to reflect argument type of the overload 2020-04-24 16:54:48 +02:00
vscode-sbt-scala https://www.apple.com 2019-09-05 14:11:07 -04:00
zinc-lm-integration/src integrate with VirtualFile changes 2020-04-24 17:44:14 -04:00
.appveyor.yml Add installNativeThinClient task 2020-08-06 07:58:53 -07:00
.gitattributes Contraband 0.4.6 2020-04-24 17:44:15 -04:00
.gitignore Update .gitignore for metals support 2020-05-16 09:52:20 +02:00
.java-version Configure JVM 1.8 in .java-version 2016-10-07 08:48:23 -05:00
.mailmap Add mailmap 2019-06-11 09:30:14 +02:00
.scalafmt.conf Set `lineEndings = preserve` in .scalafmt.conf 2020-06-29 08:15:24 -07:00
.travis.yml Check server test project scalafmt on travis 2020-08-05 18:14:11 -07:00
CONTRIBUTING.md https://www.scala-sbt.org 2019-09-05 14:11:13 -04:00
DEVELOPING.md Merge pull request #5041 from jsoref/https 2020-06-14 17:34:58 -04:00
LICENSE Apache License 2.0 2018-09-14 03:38:58 -04:00
NOTICE Apache License 2.0 2018-09-14 03:38:58 -04:00
PROFILING.md fix typo 2018-07-08 22:18:57 +09:00
README.md Merge pull request #5041 from jsoref/https 2020-06-14 17:34:58 -04:00
SUPPORT.md Split support into SUPPORT.md 2018-04-25 14:55:09 +01:00
build.sbt Add internal multi logger implementation 2020-08-09 11:20:34 -07:00
reset.sh 1.0.3-SNAPSHOT 2017-09-16 15:52:58 -04:00
sbt-allsources.sh Bump underlying modules to latest 2017-03-23 12:41:24 -04:00
server.md setting query is "sbt/setting" 2017-10-03 01:45:06 -04:00

README.md

Build Status Latest version Gitter Chat

sbt

sbt is a build tool for Scala, Java, and more.

For general documentation, see https://www.scala-sbt.org/.

sbt 1.x

This is the 1.x series of sbt. The source code of sbt is split across several GitHub repositories, including this one.

  • sbt/io hosts sbt.io module.
  • sbt/librarymanagement hosts sbt.librarymanagement module that wraps Ivy.
  • sbt/zinc hosts Zinc, an incremental compiler for Scala.
  • sbt/sbt, this repository hosts modules that implements the build tool.
  • Setup: Describes getting started with the latest binary release.
  • FAQ: Explains how to get help and more.
  • sbt/sbt-zero-seven: hosts sbt 0.7.7 and earlier versions

Issues and Pull Requests

Please read CONTRIBUTING carefully before opening a GitHub Issue.

The short version: try searching or asking on StackOverflow.

license

See LICENSE.