Commit 9c395884 authored by Kunshan Wang's avatar Kunshan Wang

Allow logback XML configuration

This will give the user more control over logging in Holstein.
Specifically, the XML configuration can configure appenders so that logs
can be written into stderr instead of stdout.
parent 9162db02
......@@ -241,7 +241,20 @@ globalSize must be a multiple of 32768 bytes (32K).*
[mu-client-pypy](https://gitlab.anu.edu.au/mu/mu-client-pypy/) project to
work. default: false
*Log levels can be: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. Case-insensitive.
Holstein uses the [logback](https://logback.qos.ch/) framework as its logging
backend. Logs can be configured using XML configuration by specifying the
following option:
- **logbackConfig**: The path to the logback XML configuration file.
Example:
```
./tools/runmu.sh --logbackConfig=./logging/logging.xml -- ./target/boot-image-echo.muref Hello world!
```
Alternatively, you can set the log level using the following options. *Log
levels can be: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. Case-insensitive.
Setting to WARN should get rid of most logging information, except the serious
ones.* The default log level is DEBUG.
......
<!-- This is an example. Make a copy of this file, and modify it for your need. -->
<configuration>
<!-- Set debug="true" to enable debugging for the logback logging framework itself -->
<!-- configuration debug="true" -->
<!-- This appender writes into stdout -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="uvm.refimpl.itpr" level="DEBUG" />
<!-- This appender writes into stderr -->
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Loggers are organised by packages. uvm includes everything in Holstein. -->
<logger name="uvm" level="INFO" />
<logger name="uvm.refimpl.itpr" level="INFO" /> <!-- Set this to DEBUG to print execution traces. -->
<logger name="uvm.refimpl.mem" level="INFO" /> <!-- Set this to DEBUG to print GC logs. -->
<root level="INFO">
<appender-ref ref="STDERR" />
</root>
</configuration>
<!--
vim: ts=2 sw=2 sts=2 et
-->
......@@ -8,13 +8,15 @@ package uvm.refimpl
import scala.collection.mutable.ArrayBuffer
import uvm.refimpl.mem.TypeSizes._
import org.slf4j.LoggerFactory
import ch.qos.logback.classic.joran.JoranConfigurator
import ch.qos.logback.classic.LoggerContext
class VMOption[+T](
val name: String,
val desc: String,
val parser: String => T,
val default: T
) {
val default: T) {
def maybeParse(maybeStr: Option[String]): T = {
maybeStr.map(parser).getOrElse(default)
}
......@@ -30,19 +32,19 @@ object VMConfParser {
case 'M' => Some(1024L * 1024L)
case 'G' => Some(1024L * 1024L * 1024L)
case 'T' => Some(1024L * 1024L * 1024L * 1024L)
case _ => None
case _ => None
}
multiplier match {
case Some(m) => str.init.toLong * m
case None => str.toLong
}
case None => str.toLong
}
}
def parseBoolean(str: String): Boolean = {
str.toLowerCase().toBoolean
}
def parseColonSeparatedList(str: String): Seq[String] = {
str.split(":")
}
......@@ -50,138 +52,155 @@ object VMConfParser {
def parseMaybeString(str: String): Option[String] = {
Some(str)
}
val options = new ArrayBuffer[VMOption[Any]]
def opt[T](
name: String,
desc: String,
parser: String => T,
default: T
): VMOption[T] = {
default: T): VMOption[T] = {
val option = new VMOption[T](name, desc, parser, default)
options += option
option
}
val sosSize = opt[Long](
name = "sosSize",
desc = """The size of the small object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.sosSize)
name = "sosSize",
desc = """The size of the small object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.sosSize)
val losSize = opt[Long](
name = "losSize",
desc = """The size of the large object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.losSize)
name = "losSize",
desc = """The size of the large object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.losSize)
val globalSize = opt[Long](
name = "globalSize",
desc = """The size of the large object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.globalSize)
name = "globalSize",
desc = """The size of the large object space in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.globalSize)
val stackSize = opt[Long](
name = "stackSize",
desc = """The size of each stack in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.stackSize)
name = "stackSize",
desc = """The size of each stack in bytes. May have suffix K, M, G or T. 1K = 1024B""",
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.stackSize)
val dumpBundle = opt[Boolean](
name = "dumpBundle",
desc = """Dump the bundle when a bundle is loaded.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.dumpBundle)
name = "dumpBundle",
desc = """Dump the bundle when a bundle is loaded.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.dumpBundle)
val staticCheck = opt[Boolean](
name = "staticCheck",
desc = """Run static checker after each bundle is loaded.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.staticCheck)
name = "staticCheck",
desc = """Run static checker after each bundle is loaded.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.staticCheck)
val sourceInfo = opt[Boolean](
name = "sourceInfo",
desc = """Provide line/column info in Mu IR when errors occur. May significantly slow down parsing!!!""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.sourceInfo)
name = "sourceInfo",
desc = """Provide line/column info in Mu IR when errors occur. May significantly slow down parsing!!!""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.sourceInfo)
val automagicReloc = opt[Boolean](
name = "automagicReloc",
desc = """'Automagic' relocation. Affects boot image building, but not loading.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.automagicReloc)
name = "automagicReloc",
desc = """'Automagic' relocation. Affects boot image building, but not loading.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.automagicReloc)
val extraLibs = opt[Seq[String]](
name = "extraLibs",
desc = """Extra libraries to load when starting the micro VM. This is a colon-separated list of libraries.
name = "extraLibs",
desc = """Extra libraries to load when starting the micro VM. This is a colon-separated list of libraries.
Each is passed to the dlsym function.""",
parser = parseColonSeparatedList,
default = VMConf.DEFAULT_CONF.extraLibs)
parser = parseColonSeparatedList,
default = VMConf.DEFAULT_CONF.extraLibs)
val bootImg = opt[Option[String]](
name = "bootImg",
desc = """The path to the boot image.""",
parser = parseMaybeString,
default = VMConf.DEFAULT_CONF.bootImg)
name = "bootImg",
desc = """The path to the boot image.""",
parser = parseMaybeString,
default = VMConf.DEFAULT_CONF.bootImg)
val logbackConfig = opt[String](
name = "logbackConfig",
desc = """The logback XML configuration file""",
parser = identity,
default = "")
val vmLog = opt[String](
name = "vmLog",
desc = """The log level of the micro VM. Can be ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF""",
parser = identity,
default = "WARN")
name = "vmLog",
desc = """The log level of the micro VM. Can be ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF""",
parser = identity,
default = "WARN")
val gcLog = opt[String](
name = "gcLog",
desc = """The log level of the garbage collector. Can be ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF""",
parser = identity,
default = "ERROR")
name = "gcLog",
desc = """The log level of the garbage collector. Can be ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF""",
parser = identity,
default = "ERROR")
val uPtrHack = opt[Boolean](
name = "uPtrHack",
desc = """Allow memory locations of general reference types to be accessed by uptr""",
parser = parseBoolean,
default = false)
name = "uPtrHack",
desc = """Allow memory locations of general reference types to be accessed by uptr""",
parser = parseBoolean,
default = false)
}
object VMConf {
val DEFAULT_CONF = new VMConf()
val ReComment = """^\s*#.*$""".r
val ReBlank = """^\s*$""".r
val ReConf = """^\s*(\w+)=(\S+)\s*$""".r
def apply(confStr: String): VMConf = {
val kvs = confStr.lines.map {
case ReComment() => None
case ReBlank() => None
case ReComment() => None
case ReBlank() => None
case ReConf(key, value) => Some((key, value))
}.flatten
val map = kvs.toMap
apply(map)
}
def apply(kvMap: Map[String, String]): VMConf = {
kvMap.get("vmLog") foreach { value => setLog("uvm", value) }
kvMap.get("gcLog") foreach { value => setLog("uvm.refimpl.mem", value) }
configureLog(kvMap)
new VMConf(
sosSize = VMConfParser.sosSize(kvMap),
losSize = VMConfParser.losSize(kvMap),
globalSize = VMConfParser.globalSize(kvMap),
stackSize = VMConfParser.stackSize(kvMap),
dumpBundle = VMConfParser.dumpBundle(kvMap),
staticCheck = VMConfParser.staticCheck(kvMap),
sourceInfo = VMConfParser.sourceInfo(kvMap),
automagicReloc = VMConfParser.automagicReloc(kvMap),
extraLibs = VMConfParser.extraLibs(kvMap),
bootImg = VMConfParser.bootImg(kvMap),
uPtrHack = VMConfParser.uPtrHack(kvMap)
)
sosSize = VMConfParser.sosSize(kvMap),
losSize = VMConfParser.losSize(kvMap),
globalSize = VMConfParser.globalSize(kvMap),
stackSize = VMConfParser.stackSize(kvMap),
dumpBundle = VMConfParser.dumpBundle(kvMap),
staticCheck = VMConfParser.staticCheck(kvMap),
sourceInfo = VMConfParser.sourceInfo(kvMap),
automagicReloc = VMConfParser.automagicReloc(kvMap),
extraLibs = VMConfParser.extraLibs(kvMap),
bootImg = VMConfParser.bootImg(kvMap),
uPtrHack = VMConfParser.uPtrHack(kvMap))
}
def configureLog(kvMap: Map[String, String]): Unit = {
kvMap.get("logbackConfig") foreach { filename =>
val context = LoggerFactory.getILoggerFactory().asInstanceOf[LoggerContext]
context.reset()
val configurator = new JoranConfigurator();
configurator.setContext(context);
configurator.doConfigure(filename);
}
kvMap.get("vmLog") foreach { value => setLog("uvm", value) }
kvMap.get("gcLog") foreach { value => setLog("uvm.refimpl.mem", value) }
}
def setLog(name: String, levelStr: String): Unit = {
import ch.qos.logback.classic.{ Level, Logger => LLogger }
import ch.qos.logback.classic.Level._
......@@ -204,6 +223,5 @@ class VMConf(
val automagicReloc: Boolean = false,
val extraLibs: Seq[String] = Seq(),
val bootImg: Option[String] = None,
val uPtrHack: Boolean = false
)
val uPtrHack: Boolean = false)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment