Skip to content

Commit

Permalink
Add logging command line option to ledger http service (#9581)
Browse files Browse the repository at this point in the history
CHANGELOG_BEGIN

- [Ledger HTTP Json service] Logging can now be configured via the `--log-level` cli argument. Valid values are `error`, `warn`, `info` (default), `debug`, `trace`

CHANGELOG_END

Co-authored-by: victor.mueller@digitalasset.com <mueller.vpr@gmail.com>
  • Loading branch information
victormueller-da and realvictorprm authored May 5, 2021
1 parent 409833f commit 26a53d8
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ trait JsonApiFixture
override val accessTokenFile = Some(jsonAccessTokenFile)
override val allowNonHttps = true
override val nonRepudiation = nonrepudiation.Configuration.Cli.Empty
override val logLevel = None
}
HttpService
.start(config)(
Expand Down
1 change: 1 addition & 0 deletions ledger-service/http-json-cli/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ da_scala_library(
"//ledger-service/cli-opts",
"//ledger-service/utils",
"//ledger/ledger-api-common",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:io_netty_netty_handler",
"@maven//:org_slf4j_slf4j_api",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import scalaz.{Show, \/}
import scala.concurrent.duration._
import scala.util.Try

import ch.qos.logback.classic.{Level => LogLevel}

// The internal transient scopt structure *and* StartSettings; external `start`
// users should extend StartSettings or DefaultStartSettings themselves
private[http] final case class Config(
Expand All @@ -36,6 +38,7 @@ private[http] final case class Config(
accessTokenFile: Option[Path] = None,
wsConfig: Option[WebsocketConfig] = None,
nonRepudiation: nonrepudiation.Configuration.Cli = nonrepudiation.Configuration.Cli.Empty,
logLevel: Option[LogLevel] = None, // the default is in logback.xml
) extends StartSettings

private[http] object Config {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import scopt.{Read, RenderingMode}
import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.util.Try

import ch.qos.logback.classic.{Level => LogLevel}

class OptionParser(getEnvVar: String => Option[String], supportedJdbcDriverNames: Set[String])
extends scopt.OptionParser[Config]("http-json-binary")
with StrictLogging {
Expand Down Expand Up @@ -47,6 +49,9 @@ class OptionParser(getEnvVar: String => Option[String], supportedJdbcDriverNames

override def renderingMode: RenderingMode = RenderingMode.OneColumn

// TODO: Refactor out as this is duplicated from the sandbox code
private val KnownLogLevels = Set("ERROR", "WARN", "INFO", "DEBUG", "TRACE")

head("HTTP JSON API daemon")

help("help").text("Print this usage text")
Expand Down Expand Up @@ -165,4 +170,16 @@ class OptionParser(getEnvVar: String => Option[String], supportedJdbcDriverNames
.optional()
.valueName(WebsocketConfig.usage)
.text(s"Optional websocket configuration string. ${WebsocketConfig.help}")

// TODO: Refactor out as this is duplicated from the sandbox code
opt[String]("log-level")
.optional()
.validate(l =>
Either
.cond(KnownLogLevels.contains(l.toUpperCase), (), s"Unrecognized logging level $l")
)
.action((level, c) => c.copy(logLevel = Some(LogLevel.toLevel(level.toUpperCase))))
.text(
"Default logging level to use. Available values are INFO, TRACE, DEBUG, WARN, and ERROR. Defaults to INFO."
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import com.daml.ledger.api.tls.TlsConfiguration

import scala.concurrent.duration.FiniteDuration

import ch.qos.logback.classic.{Level => LogLevel}

// defined separately from Config so
// 1. it is absolutely lexically apparent what `import startSettings._` means
// 2. avoid incorporating other Config'd things into "the shared args to start"
Expand All @@ -28,6 +30,7 @@ trait StartSettings {
val maxInboundMessageSize: Int
val healthTimeoutSeconds: Int
val nonRepudiation: nonrepudiation.Configuration.Cli
val logLevel: Option[LogLevel]
}

object StartSettings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ object Main extends StrictLogging {
val StartupError = 101
}

// TODO: Refactor out as this is duplicated from the sandbox code
object Logging {

import ch.qos.logback.classic.{Level => LogLevel}
import org.slf4j.{Logger, LoggerFactory}

def setGlobalLogLevel(verbosity: LogLevel): Unit = {
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) match {
case rootLogger: ch.qos.logback.classic.Logger =>
rootLogger.setLevel(verbosity)
rootLogger.info(s"Verbosity changed to $verbosity")
case _ =>
logger.warn(s"Verbosity cannot be set to requested $verbosity")
}
}
}

def main(args: Array[String]): Unit =
Cli.parseConfig(
args,
Expand All @@ -43,6 +60,7 @@ object Main extends StrictLogging {
}

private def main(config: Config): Unit = {
config.logLevel.foreach(Logging.setGlobalLogLevel(_))
logger.info(
s"Config(ledgerHost=${config.ledgerHost: String}, ledgerPort=${config.ledgerPort: Int}" +
s", address=${config.address: String}, httpPort=${config.httpPort: Int}" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,48 @@ final class CliSpec extends AnyFreeSpec with Matchers {
val sharedOptions =
Seq("--ledger-host", "localhost", "--ledger-port", "6865", "--http-port", "7500")

"LogLevel" - {
import ch.qos.logback.classic.{Level => LogLevel}

def logLevelArgs(level: String) = Seq("--log-level", level)

def checkLogLevelWorks(level: String, expected: LogLevel) = {
val config = configParser(logLevelArgs(level) ++ sharedOptions)
.getOrElse(fail())
config.logLevel shouldBe Some(expected)
}

"should get the error log level from the command line argument when provided" in {
checkLogLevelWorks("error", LogLevel.ERROR)
}

"should get the warn log level from the command line argument when provided" in {
checkLogLevelWorks("warn", LogLevel.WARN)
}

"should get the info log level from the command line argument when provided" in {
checkLogLevelWorks("info", LogLevel.INFO)
}

"should get the debug log level from the command line argument when provided" in {
checkLogLevelWorks("debug", LogLevel.DEBUG)
}

"should get the trace log level from the command line argument when provided" in {
checkLogLevelWorks("trace", LogLevel.TRACE)
}

"shouldn't get a config parser result if an invalid log level is provided via a command line argument" in {
val config = configParser(logLevelArgs("SUPERFANCYLOGLEVEL") ++ sharedOptions)
config shouldBe None
}

"should get a config parser result if no log level is provided via a command line argument" in {
val config = configParser(sharedOptions).getOrElse(fail())
config.logLevel shouldBe None
}
}

"JdbcConfig" - {
"should get the jdbc string from the command line argument when provided" in {
val config = configParser(Seq("--query-store-jdbc-config", jdbcConfigString) ++ sharedOptions)
Expand Down

0 comments on commit 26a53d8

Please sign in to comment.