diff --git a/app/server/src/main/resources/logback.xml b/app/server/src/main/resources/logback.xml index 5d9e0431c0..55c5b41108 100644 --- a/app/server/src/main/resources/logback.xml +++ b/app/server/src/main/resources/logback.xml @@ -10,4 +10,28 @@ + + + + %date{yyyy-MM-dd'T'HH:mm:ss,SSXXX} %level [%logger{0}] %msg%n + + + + + 8192 + true + + + + + ${bitcoins.log.location} + + %date{yyyy-MM-dd'T'HH:mm:ss,SSXXX} %level [%logger{0}] %msg%n + + + + + + + \ No newline at end of file diff --git a/app/server/src/main/resources/reference.conf b/app/server/src/main/resources/reference.conf index 638688e3e7..888ec6e5c8 100644 --- a/app/server/src/main/resources/reference.conf +++ b/app/server/src/main/resources/reference.conf @@ -90,8 +90,27 @@ bitcoin-s { akka { - loglevel = "INFO" - stdout-loglevel = "OFF" + # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs + # to STDOUT) + loggers = ["akka.event.slf4j.Slf4jLogger"] + + # Log level used by the configured loggers (see "loggers") as soon + # as they have been started; before that, see "stdout-loglevel" + # Options: OFF, ERROR, WARNING, INFO, DEBUG + loglevel = "DEBUG" + + # Log level for the very basic logger activated during ActorSystem startup. + # This logger prints the log messages to stdout (System.out). + # Options: OFF, ERROR, WARNING, INFO, DEBUG + stdout-loglevel = "DEBUG" + + # Filter of log events that is used by the LoggingAdapter before + # publishing log events to the eventStream. + logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" + + use-slf4j = on + + log-config-on-start = off actor { debug { diff --git a/app/server/src/main/scala/org/bitcoins/server/Main.scala b/app/server/src/main/scala/org/bitcoins/server/Main.scala index f64095ef28..d1bf5c37b9 100644 --- a/app/server/src/main/scala/org/bitcoins/server/Main.scala +++ b/app/server/src/main/scala/org/bitcoins/server/Main.scala @@ -1,6 +1,6 @@ package org.bitcoins.server -import java.nio.file.Paths +import java.nio.file.{Path, Paths} import akka.actor.ActorSystem import akka.dispatch.Dispatchers @@ -14,6 +14,7 @@ import org.bitcoins.chain.models.{ CompactFilterHeaderDAO } import org.bitcoins.core.Core +import org.bitcoins.core.config.{BitcoinNetworks, MainNet, RegTest, TestNet3} import org.bitcoins.core.util.{BitcoinSLogger, FutureUtil, NetworkUtil} import org.bitcoins.db.AppConfig import org.bitcoins.feeprovider.BitcoinerLiveFeeRateProvider @@ -28,21 +29,41 @@ import scala.concurrent.{ExecutionContext, Future, Promise} object Main extends App with BitcoinSLogger { private def runMain(): Unit = { - implicit val system: ActorSystem = ActorSystem("bitcoin-s") - implicit val ec: ExecutionContext = system.dispatcher val argsWithIndex = args.zipWithIndex - implicit val conf: BitcoinSAppConfig = { + val dataDirIndexOpt = { + argsWithIndex.find(_._1.toLowerCase == "--datadir") + } + val datadirPath = dataDirIndexOpt match { + case None => AppConfig.DEFAULT_BITCOIN_S_DATADIR + case Some((_, dataDirIndex)) => + val str = args(dataDirIndex + 1) + Paths.get(str) + } - val dataDirIndexOpt = { - argsWithIndex.find(_._1.toLowerCase == "--datadir") - } - val datadirPath = dataDirIndexOpt match { - case None => AppConfig.DEFAULT_BITCOIN_S_DATADIR - case Some((_, dataDirIndex)) => - val str = args(dataDirIndex + 1) - Paths.get(str) + val baseConfig = AppConfig.getBaseConfig(datadirPath) + + val networkStr = baseConfig.getString("bitcoin-s.network") + val network = BitcoinNetworks.fromString(networkStr) + + val datadir: Path = { + val lastDirname = network match { + case MainNet => "mainnet" + case TestNet3 => "testnet3" + case RegTest => "regtest" } + datadirPath.resolve(lastDirname) + } + + System.setProperty("bitcoins.log.location", + datadir.resolve("bitcoin-s.log").toAbsolutePath.toString) + + implicit val system: ActorSystem = ActorSystem("bitcoin-s", baseConfig) + implicit val ec: ExecutionContext = system.dispatcher + + system.log.info("Akka logger started") + + implicit val conf: BitcoinSAppConfig = { BitcoinSAppConfig(datadirPath) } diff --git a/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala b/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala index e56a950896..108b9f1365 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala @@ -135,90 +135,17 @@ abstract class AppConfig extends LoggerConfig with StartStopAsync[Unit] { * The underlying config that we derive the * rest of the fields in this class from */ + private[bitcoins] lazy val baseConfig: Config = { + AppConfig.getBaseConfig(baseDatadir, configOverrides) + } + private[bitcoins] lazy val config: Config = { - - val datadirConfig = { - val file = baseDatadir.resolve("bitcoin-s.conf") - val config = if (Files.isReadable(file)) { - ConfigFactory.parseFile(file.toFile()) - } else { - ConfigFactory.empty() - } - - val withDatadir = - ConfigFactory.parseString(s"bitcoin-s.datadir = $baseDatadir") - withDatadir.withFallback(config) - } - - logger.trace(s"Data directory config:") - if (datadirConfig.hasPath("bitcoin-s")) { - logger.trace(datadirConfig.getConfig("bitcoin-s").asReadableJson) - } else { - logger.trace(ConfigFactory.empty().asReadableJson) - } - - // `load` tries to resolve substitions, - // `parseResources` does not - val dbConfig = ConfigFactory - .parseResources("db.conf") - - logger.trace( - s"DB config: ${dbConfig.getConfig("bitcoin-s").asReadableJson}") - - // we want to NOT resolve substitutions in the configuraton until the user - // provided configs also has been loaded. .parseResources() does not do that - // whereas .load() does - val classPathConfig = { - val applicationConf = ConfigFactory.parseResources("application.conf") - val referenceConf = ConfigFactory.parseResources("reference.conf") - applicationConf.withFallback(referenceConf) - } - - logger.trace( - s"Classpath config: ${classPathConfig.getConfig("bitcoin-s").asReadableJson}") - - // we want the data directory configuration - // to take preference over any bundled (classpath) - // configurations - // loads reference.conf (provided by Bitcoin-S) - val unresolvedConfig = datadirConfig - .withFallback(classPathConfig) - .withFallback(dbConfig) - - logger.trace(s"Unresolved bitcoin-s config:") - logger.trace(unresolvedConfig.getConfig("bitcoin-s").asReadableJson) - - val withOverrides = - if (configOverrides.nonEmpty) { - val overrides = - configOverrides - // we reverse to make the configs specified last take precedent - .reverse - .reduce(_.withFallback(_)) - - val interestingOverrides = overrides.getConfig("bitcoin-s") - logger.trace( - s"${configOverrides.length} user-overrides for bitcoin-s config:") - logger.trace(interestingOverrides.asReadableJson) - - // to make the overrides actually override - // the default setings we have to do it - // in this order - overrides.withFallback(unresolvedConfig) - } else { - logger.trace(s"No user-provided overrides") - unresolvedConfig - } - - val finalConfig = withOverrides - .resolve() - .getConfig("bitcoin-s") + val finalConfig = baseConfig.getConfig("bitcoin-s") logger.debug(s"Resolved bitcoin-s config:") logger.debug(finalConfig.asReadableJson) finalConfig - } /** The base data directory. This is where we look for a configuration file */ @@ -234,7 +161,12 @@ abstract class AppConfig extends LoggerConfig with StartStopAsync[Unit] { baseDatadir.resolve(lastDirname) } - override val logFile: Path = datadir.resolve("bitcoin-s.log") + override val logFile: Path = { + val path = datadir.resolve("bitcoin-s.log") + // Set property for loggers + System.setProperty("bitcoins.log.location", path.toAbsolutePath.toString) + path + } private def stringToLogLevel(str: String): Option[Level] = str.toLowerCase() match { @@ -315,6 +247,64 @@ abstract class AppConfig extends LoggerConfig with StartStopAsync[Unit] { object AppConfig extends BitcoinSLogger { + def getBaseConfig( + baseDatadir: Path, + configOverrides: List[Config] = List.empty): Config = { + val datadirConfig = { + val file = baseDatadir.resolve("bitcoin-s.conf") + val config = if (Files.isReadable(file)) { + ConfigFactory.parseFile(file.toFile) + } else { + ConfigFactory.empty() + } + + val withDatadir = + ConfigFactory.parseString(s"bitcoin-s.datadir = $baseDatadir") + withDatadir.withFallback(config) + } + + // `load` tries to resolve substitions, + // `parseResources` does not + val dbConfig = ConfigFactory + .parseResources("db.conf") + + // we want to NOT resolve substitutions in the configuraton until the user + // provided configs also has been loaded. .parseResources() does not do that + // whereas .load() does + val classPathConfig = { + val applicationConf = ConfigFactory.parseResources("application.conf") + val referenceConf = ConfigFactory.parseResources("reference.conf") + applicationConf.withFallback(referenceConf) + } + + // we want the data directory configuration + // to take preference over any bundled (classpath) + // configurations + // loads reference.conf (provided by Bitcoin-S) + val unresolvedConfig = datadirConfig + .withFallback(classPathConfig) + .withFallback(dbConfig) + + val withOverrides = + if (configOverrides.nonEmpty) { + val overrides = + configOverrides + // we reverse to make the configs specified last take precedent + .reverse + .reduce(_.withFallback(_)) + + // to make the overrides actually override + // the default setings we have to do it + // in this order + overrides.withFallback(unresolvedConfig) + } else { + unresolvedConfig + } + + withOverrides + .resolve() + } + /** The default data directory * * TODO: use different directories on Windows and Mac, diff --git a/project/Deps.scala b/project/Deps.scala index 3cc6dd2607..7d2b659732 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -8,7 +8,8 @@ object Deps { val scalacheck = "1.14.3" val scalaTest = "3.2.0" - val scalaTestPlus = "3.2.1.0" //super annoying... https://oss.sonatype.org/content/groups/public/org/scalatestplus/ + val scalaTestPlus = + "3.2.1.0" //super annoying... https://oss.sonatype.org/content/groups/public/org/scalatestplus/ val slf4j = "1.7.30" val spray = "1.3.5" val zeromq = "0.5.2" @@ -56,29 +57,62 @@ object Deps { object Compile { - val bouncycastle = "org.bouncycastle" % "bcprov-jdk15on" % V.bouncyCastle withSources () withJavadoc () - val scodec = "org.scodec" %% "scodec-bits" % V.scodecV withSources () withJavadoc () - val slf4j = "org.slf4j" % "slf4j-api" % V.slf4j % "provided" withSources () withJavadoc () - val zeromq = "org.zeromq" % "jeromq" % V.zeromq withSources () withJavadoc () - val akkaHttp = "com.typesafe.akka" %% "akka-http" % V.akkav withSources () withJavadoc () - val akkaStream = "com.typesafe.akka" %% "akka-stream" % V.akkaStreamv withSources () withJavadoc () - val akkaActor = "com.typesafe.akka" %% "akka-actor" % V.akkaStreamv withSources () withJavadoc () + val bouncycastle = + "org.bouncycastle" % "bcprov-jdk15on" % V.bouncyCastle withSources () withJavadoc () + + val scodec = + "org.scodec" %% "scodec-bits" % V.scodecV withSources () withJavadoc () + + val slf4j = + "org.slf4j" % "slf4j-api" % V.slf4j % "provided" withSources () withJavadoc () + + val zeromq = + "org.zeromq" % "jeromq" % V.zeromq withSources () withJavadoc () + + val akkaHttp = + "com.typesafe.akka" %% "akka-http" % V.akkav withSources () withJavadoc () + + val akkaStream = + "com.typesafe.akka" %% "akka-stream" % V.akkaStreamv withSources () withJavadoc () + + val akkaActor = + "com.typesafe.akka" %% "akka-actor" % V.akkaStreamv withSources () withJavadoc () + + val akkaSlf4j = + "com.typesafe.akka" %% "akka-slf4j" % V.akkaStreamv withSources () withJavadoc () + + val scalaFx = + "org.scalafx" %% "scalafx" % V.scalaFxV withSources () withJavadoc () - val scalaFx = "org.scalafx" %% "scalafx" % V.scalaFxV withSources () withJavadoc () lazy val osName = System.getProperty("os.name") match { case n if n.startsWith("Linux") => "linux" case n if n.startsWith("Mac") => "mac" case n if n.startsWith("Windows") => "win" case _ => throw new Exception("Unknown platform!") } + // Not sure if all of these are needed, some might be possible to remove - lazy val javaFxBase = "org.openjfx" % s"javafx-base" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxControls = "org.openjfx" % s"javafx-controls" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxFxml = "org.openjfx" % s"javafx-fxml" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxGraphics = "org.openjfx" % s"javafx-graphics" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxMedia = "org.openjfx" % s"javafx-media" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxSwing = "org.openjfx" % s"javafx-swing" % V.javaFxV classifier osName withSources () withJavadoc () - lazy val javaFxWeb = "org.openjfx" % s"javafx-web" % V.javaFxV classifier osName withSources () withJavadoc () + lazy val javaFxBase = + "org.openjfx" % s"javafx-base" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxControls = + "org.openjfx" % s"javafx-controls" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxFxml = + "org.openjfx" % s"javafx-fxml" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxGraphics = + "org.openjfx" % s"javafx-graphics" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxMedia = + "org.openjfx" % s"javafx-media" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxSwing = + "org.openjfx" % s"javafx-swing" % V.javaFxV classifier osName withSources () withJavadoc () + + lazy val javaFxWeb = + "org.openjfx" % s"javafx-web" % V.javaFxV classifier osName withSources () withJavadoc () + lazy val javaFxDeps = List(javaFxBase, javaFxControls, javaFxFxml, @@ -87,16 +121,23 @@ object Deps { javaFxSwing, javaFxWeb) - val playJson = "com.typesafe.play" %% "play-json" % V.playv withSources () withJavadoc () - val typesafeConfig = "com.typesafe" % "config" % V.typesafeConfigV withSources () withJavadoc () + val playJson = + "com.typesafe.play" %% "play-json" % V.playv withSources () withJavadoc () - val logback = "ch.qos.logback" % "logback-classic" % V.logback withSources () withJavadoc () + val typesafeConfig = + "com.typesafe" % "config" % V.typesafeConfigV withSources () withJavadoc () + + val logback = + "ch.qos.logback" % "logback-classic" % V.logback withSources () withJavadoc () val codehaus = "org.codehaus.janino" % "janino" % V.codehausV + //for loading secp256k1 natively - val nativeLoader = "org.scijava" % "native-lib-loader" % V.nativeLoaderV withSources () withJavadoc () + val nativeLoader = + "org.scijava" % "native-lib-loader" % V.nativeLoaderV withSources () withJavadoc () //node deps - val slick = "com.typesafe.slick" %% "slick" % V.slickV withSources () withJavadoc () + val slick = + "com.typesafe.slick" %% "slick" % V.slickV withSources () withJavadoc () val slickHikari = "com.typesafe.slick" %% "slick-hikaricp" % V.slickV val sqlite = "org.xerial" % "sqlite-jdbc" % V.sqliteV val postgres = "org.postgresql" % "postgresql" % V.postgresV @@ -115,26 +156,49 @@ object Deps { // HTTP client lib val sttp = "com.softwaremill.sttp" %% "core" % V.sttpV - val scalacheck = "org.scalacheck" %% "scalacheck" % V.scalacheck withSources () withJavadoc () - val scalaTest = "org.scalatest" %% "scalatest" % V.scalaTest withSources () withJavadoc () - val scalaTestPlus = "org.scalatestplus" %% "scalacheck-1-14" % V.scalaTestPlus withSources () withJavadoc () - val pgEmbedded = "com.opentable.components" % "otj-pg-embedded" % V.pgEmbeddedV withSources () withJavadoc () + val scalacheck = + "org.scalacheck" %% "scalacheck" % V.scalacheck withSources () withJavadoc () + + val scalaTest = + "org.scalatest" %% "scalatest" % V.scalaTest withSources () withJavadoc () + + val scalaTestPlus = + "org.scalatestplus" %% "scalacheck-1-14" % V.scalaTestPlus withSources () withJavadoc () + + val pgEmbedded = + "com.opentable.components" % "otj-pg-embedded" % V.pgEmbeddedV withSources () withJavadoc () } object Test { - val newAsync = "org.scala-lang.modules" %% "scala-async" % V.asyncNewScalaV % "test" withSources () withJavadoc () - val junitInterface = "com.novocode" % "junit-interface" % V.junitV % "test" withSources () withJavadoc () + + val newAsync = + "org.scala-lang.modules" %% "scala-async" % V.asyncNewScalaV % "test" withSources () withJavadoc () + + val junitInterface = + "com.novocode" % "junit-interface" % V.junitV % "test" withSources () withJavadoc () val logback = Compile.logback % "test" val scalacheck = Compile.scalacheck % "test" val scalaTest = Compile.scalaTest % "test" val scalaMock = "org.scalamock" %% "scalamock" % V.scalamockV - val spray = "io.spray" %% "spray-json" % V.spray % "test" withSources () withJavadoc () - val akkaHttp = "com.typesafe.akka" %% "akka-http-testkit" % V.akkav % "test" withSources () withJavadoc () - val akkaStream = "com.typesafe.akka" %% "akka-stream-testkit" % V.akkaStreamv % "test" withSources () withJavadoc () + + val spray = + "io.spray" %% "spray-json" % V.spray % "test" withSources () withJavadoc () + + val akkaHttp = + "com.typesafe.akka" %% "akka-http-testkit" % V.akkav % "test" withSources () withJavadoc () + + val akkaStream = + "com.typesafe.akka" %% "akka-stream-testkit" % V.akkaStreamv % "test" withSources () withJavadoc () val playJson = Compile.playJson % "test" - val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % V.akkaActorV withSources () withJavadoc () - val scalameter = "com.storm-enroute" %% "scalameter" % V.scalameterV % "test" withSources () withJavadoc () - val pgEmbedded = "com.opentable.components" % "otj-pg-embedded" % V.pgEmbeddedV % "test" withSources () withJavadoc () + + val akkaTestkit = + "com.typesafe.akka" %% "akka-testkit" % V.akkaActorV withSources () withJavadoc () + + val scalameter = + "com.storm-enroute" %% "scalameter" % V.scalameterV % "test" withSources () withJavadoc () + + val pgEmbedded = + "com.opentable.components" % "otj-pg-embedded" % V.pgEmbeddedV % "test" withSources () withJavadoc () } val chain = List( @@ -145,11 +209,12 @@ object Deps { Test.pgEmbedded ) - def appCommons(scalaVersion: String) = List( - Compile.newMicroPickle, - Compile.playJson, - Compile.slf4j - ) + def appCommons(scalaVersion: String) = + List( + Compile.newMicroPickle, + Compile.playJson, + Compile.slf4j + ) val core = List( Compile.bouncycastle, @@ -193,14 +258,15 @@ object Deps { Compile.typesafeConfig ) - def bitcoindRpcTest(scalaVersion: String) = List( - Test.akkaHttp, - Test.akkaStream, - Test.logback, - Test.scalaTest, - Test.scalacheck, - Test.newAsync - ) + def bitcoindRpcTest(scalaVersion: String) = + List( + Test.akkaHttp, + Test.akkaStream, + Test.logback, + Test.scalaTest, + Test.scalacheck, + Test.newAsync + ) val bench = List( "org.slf4j" % "slf4j-api" % V.slf4j withSources () withJavadoc (), @@ -219,25 +285,28 @@ object Deps { Test.pgEmbedded ) - def cli(scalaVersion: String) = List( - Compile.sttp, - Compile.newMicroPickle, - Compile.logback, - Compile.scopt, - //we can remove this dependency when this is fixed - //https://github.com/oracle/graal/issues/1943 - //see https://github.com/bitcoin-s/bitcoin-s/issues/1100 - Compile.codehaus - ) + def cli(scalaVersion: String) = + List( + Compile.sttp, + Compile.newMicroPickle, + Compile.logback, + Compile.scopt, + //we can remove this dependency when this is fixed + //https://github.com/oracle/graal/issues/1943 + //see https://github.com/bitcoin-s/bitcoin-s/issues/1100 + Compile.codehaus + ) val gui = List(Compile.scalaFx) ++ Compile.javaFxDeps - def server(scalaVersion: String) = List( - Compile.newMicroPickle, - Compile.logback, - Compile.akkaActor, - Compile.akkaHttp - ) + def server(scalaVersion: String) = + List( + Compile.newMicroPickle, + Compile.logback, + Compile.akkaActor, + Compile.akkaHttp, + Compile.akkaSlf4j + ) val eclairRpc = List( Compile.akkaHttp, @@ -288,19 +357,21 @@ object Deps { Test.akkaTestkit ) - def keyManager(scalaVersion: String) = List( - Compile.newMicroJson - ) + def keyManager(scalaVersion: String) = + List( + Compile.newMicroJson + ) val keyManagerTest = List( Compile.slf4j, Test.logback ) - def wallet(scalaVersion: String) = List( - Compile.newMicroJson, - Compile.logback - ) + def wallet(scalaVersion: String) = + List( + Compile.newMicroJson, + Compile.logback + ) val walletTest = List( Test.akkaTestkit,