From e02adb06943678a51b5cc98967ac0642801f951b Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 10 Jun 2010 21:26:27 -0400 Subject: [PATCH] first round of logger cleanup/migration --- util/log/BasicLogger.scala | 14 ++++++------ util/log/BufferedLogger.scala | 15 +++++++------ util/log/ConsoleLogger.scala | 17 +++++++++------ util/log/FilterLogger.scala | 35 ++++++++++++++++++++++++++++++ util/log/Level.scala | 10 ++++----- util/log/LogEvent.scala | 4 ++-- util/log/Logger.scala | 14 +++++++----- util/log/LoggerWriter.scala | 40 +++++++++++++++++++++++++++++++++++ util/log/MultiLogger.scala | 27 +++++++++++++++++++++++ 9 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 util/log/FilterLogger.scala create mode 100644 util/log/LoggerWriter.scala create mode 100644 util/log/MultiLogger.scala diff --git a/util/log/BasicLogger.scala b/util/log/BasicLogger.scala index 23607c8ed..a52d3b433 100644 --- a/util/log/BasicLogger.scala +++ b/util/log/BasicLogger.scala @@ -1,15 +1,15 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ - package xsbt +package sbt /** Implements the level-setting methods of Logger.*/ -abstract class BasicLogger extends Logger +abstract class BasicLogger extends AbstractLogger { - private var traceEnabledVar = true + private var traceEnabledVar = java.lang.Integer.MAX_VALUE private var level: Level.Value = Level.Info def getLevel = level def setLevel(newLevel: Level.Value) { level = newLevel } - def enableTrace(flag: Boolean) { traceEnabledVar = flag } - def traceEnabled = traceEnabledVar -} + def setTrace(level: Int) { traceEnabledVar = level } + def getTrace = traceEnabledVar +} \ No newline at end of file diff --git a/util/log/BufferedLogger.scala b/util/log/BufferedLogger.scala index 7e8348f2d..1a72e022d 100644 --- a/util/log/BufferedLogger.scala +++ b/util/log/BufferedLogger.scala @@ -1,8 +1,9 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ package xsbt + import sbt.{AbstractLogger, ControlEvent, Level, Log, LogEvent, SetLevel, SetTrace, Success, Trace} import scala.collection.mutable.ListBuffer /** A logger that can buffer the logging done on it and then can flush the buffer @@ -13,7 +14,7 @@ * * This class assumes that it is the only client of the delegate logger. * */ -class BufferedLogger(delegate: Logger) extends Logger +class BufferedLogger(delegate: AbstractLogger) extends AbstractLogger { private[this] val buffer = new ListBuffer[LogEvent] private[this] var recording = false @@ -54,10 +55,10 @@ class BufferedLogger(delegate: Logger) extends Logger } def getLevel = delegate.getLevel def traceEnabled = delegate.traceEnabled - def enableTrace(flag: Boolean) + def setTrace(level: Int) { - buffer += new SetTrace(flag) - delegate.enableTrace(flag) + buffer += new SetTrace(level) + delegate.setTrace(level) } def trace(t: => Throwable): Unit = @@ -73,9 +74,9 @@ class BufferedLogger(delegate: Logger) extends Logger delegate.logAll(events) def control(event: ControlEvent.Value, message: => String): Unit = doBufferable(Level.Info, new ControlEvent(event, message), _.control(event, message)) - private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = doBufferableIf(atLevel(level), appendIfBuffered, doUnbuffered) - private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = if(condition) { if(recording) diff --git a/util/log/ConsoleLogger.scala b/util/log/ConsoleLogger.scala index a7217f026..49db31b66 100644 --- a/util/log/ConsoleLogger.scala +++ b/util/log/ConsoleLogger.scala @@ -1,7 +1,7 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ - package xsbt +package sbt object ConsoleLogger { @@ -17,10 +17,12 @@ object ConsoleLogger } /** A logger that logs to the console. On supported systems, the level labels are -* colored. */ +* colored. +* +* This logger is not thread-safe.*/ class ConsoleLogger extends BasicLogger { - import ConsoleLogger.formatEnabled + override def ansiCodesSupported = ConsoleLogger.formatEnabled def messageColor(level: Level.Value) = Console.RESET def labelColor(level: Level.Value) = level match @@ -39,8 +41,9 @@ class ConsoleLogger extends BasicLogger def trace(t: => Throwable): Unit = System.out.synchronized { - if(traceEnabled) - t.printStackTrace + val traceLevel = getTrace + if(traceLevel >= 0) + System.out.synchronized { System.out.print(StackTrace.trimmed(t, traceLevel)) } } def log(level: Level.Value, message: => String) { @@ -49,7 +52,7 @@ class ConsoleLogger extends BasicLogger } private def setColor(color: String) { - if(formatEnabled) + if(ansiCodesSupported) System.out.synchronized { System.out.print(color) } } private def log(labelColor: String, label: String, messageColor: String, message: String): Unit = diff --git a/util/log/FilterLogger.scala b/util/log/FilterLogger.scala new file mode 100644 index 000000000..152f6bdd5 --- /dev/null +++ b/util/log/FilterLogger.scala @@ -0,0 +1,35 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + +/** A filter logger is used to delegate messages but not the logging level to another logger. This means +* that messages are logged at the higher of the two levels set by this logger and its delegate. +* */ +class FilterLogger(delegate: AbstractLogger) extends BasicLogger +{ + override lazy val ansiCodesSupported = delegate.ansiCodesSupported + def trace(t: => Throwable) + { + if(traceEnabled) + delegate.trace(t) + } + override def setTrace(level: Int) { delegate.setTrace(level) } + override def getTrace = delegate.getTrace + def log(level: Level.Value, message: => String) + { + if(atLevel(level)) + delegate.log(level, message) + } + def success(message: => String) + { + if(atLevel(Level.Info)) + delegate.success(message) + } + def control(event: ControlEvent.Value, message: => String) + { + if(atLevel(Level.Info)) + delegate.control(event, message) + } + def logAll(events: Seq[LogEvent]): Unit = delegate.logAll(events) +} diff --git a/util/log/Level.scala b/util/log/Level.scala index 86abc257d..ad4e51759 100644 --- a/util/log/Level.scala +++ b/util/log/Level.scala @@ -1,11 +1,11 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt /** An enumeration defining the levels available for logging. A level includes all of the levels * with id larger than its own id. For example, Warn (id=3) includes Error (id=4).*/ -object Level extends Enumeration with NotNull +object Level extends Enumeration { val Debug = Value(1, "debug") val Info = Value(2, "info") @@ -16,10 +16,8 @@ object Level extends Enumeration with NotNull * label is also defined here. */ val SuccessLabel = "success" - // added because elements was renamed to iterator in 2.8.0 nightly - def levels = Debug :: Info :: Warn :: Error :: Nil /** Returns the level with the given name wrapped in Some, or None if no level exists for that name. */ - def apply(s: String) = levels.find(s == _.toString) + def apply(s: String) = values.find(s == _.toString) /** Same as apply, defined for use in pattern matching. */ - private[xsbt] def unapply(s: String) = apply(s) + private[sbt] def unapply(s: String) = apply(s) } \ No newline at end of file diff --git a/util/log/LogEvent.scala b/util/log/LogEvent.scala index 19a5b24db..ffe6049d7 100644 --- a/util/log/LogEvent.scala +++ b/util/log/LogEvent.scala @@ -1,14 +1,14 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt sealed trait LogEvent extends NotNull final class Success(val msg: String) extends LogEvent final class Log(val level: Level.Value, val msg: String) extends LogEvent final class Trace(val exception: Throwable) extends LogEvent final class SetLevel(val newLevel: Level.Value) extends LogEvent -final class SetTrace(val enabled: Boolean) extends LogEvent +final class SetTrace(val level: Int) extends LogEvent final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent object ControlEvent extends Enumeration diff --git a/util/log/Logger.scala b/util/log/Logger.scala index 153596f6f..1be353c4b 100644 --- a/util/log/Logger.scala +++ b/util/log/Logger.scala @@ -1,18 +1,22 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt import xsbti.{Logger => xLogger, F0} -abstract class Logger extends xLogger with NotNull + +abstract class AbstractLogger extends xLogger with NotNull { def getLevel: Level.Value def setLevel(newLevel: Level.Value) - def enableTrace(flag: Boolean) - def traceEnabled: Boolean + def setTrace(flag: Int) + def getTrace: Int + final def traceEnabled = getTrace >= 0 + def ansiCodesSupported = false def atLevel(level: Level.Value) = level.id >= getLevel.id def trace(t: => Throwable): Unit + final def verbose(message: => String): Unit = debug(message) final def debug(message: => String): Unit = log(Level.Debug, message) final def info(message: => String): Unit = log(Level.Info, message) final def warn(message: => String): Unit = log(Level.Warn, message) @@ -31,7 +35,7 @@ abstract class Logger extends xLogger with NotNull case l: Log => log(l.level, l.msg) case t: Trace => trace(t.exception) case setL: SetLevel => setLevel(setL.newLevel) - case setT: SetTrace => enableTrace(setT.enabled) + case setT: SetTrace => setTrace(setT.level) case c: ControlEvent => control(c.event, c.msg) } } diff --git a/util/log/LoggerWriter.scala b/util/log/LoggerWriter.scala new file mode 100644 index 000000000..b3b2d54d3 --- /dev/null +++ b/util/log/LoggerWriter.scala @@ -0,0 +1,40 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + +/** Provides a `java.io.Writer` interface to a `Logger`. Content is line-buffered and logged at `level`. +* A line is delimited by `nl`, which is by default the platform line separator.*/ +class LoggerWriter(delegate: AbstractLogger, level: Level.Value, nl: String) extends java.io.Writer +{ + def this(delegate: AbstractLogger, level: Level.Value) = this(delegate, level, System.getProperty("line.separator")) + + private[this] val buffer = new StringBuilder + + override def close() = flush() + override def flush(): Unit = + synchronized { + if(buffer.length > 0) + { + log(buffer.toString) + buffer.clear() + } + } + override def write(content: Array[Char], offset: Int, length: Int): Unit = + synchronized { + buffer.append(content, offset, length) + process() + } + + private[this] def process() + { + val i = buffer.indexOf(nl) + if(i >= 0) + { + log(buffer.substring(0, i)) + buffer.delete(0, i + nl.length) + process() + } + } + private[this] def log(s: String): Unit = delegate.log(level, s) +} \ No newline at end of file diff --git a/util/log/MultiLogger.scala b/util/log/MultiLogger.scala new file mode 100644 index 000000000..800d170ed --- /dev/null +++ b/util/log/MultiLogger.scala @@ -0,0 +1,27 @@ + +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + + +class MultiLogger(delegates: List[AbstractLogger]) extends BasicLogger +{ + override lazy val ansiCodesSupported = delegates.forall(_.ansiCodesSupported) + override def setLevel(newLevel: Level.Value) + { + super.setLevel(newLevel) + dispatch(new SetLevel(newLevel)) + } + override def setTrace(level: Int) + { + super.setTrace(level) + dispatch(new SetTrace(level)) + } + def trace(t: => Throwable) { dispatch(new Trace(t)) } + def log(level: Level.Value, message: => String) { dispatch(new Log(level, message)) } + def success(message: => String) { dispatch(new Success(message)) } + def logAll(events: Seq[LogEvent]) { delegates.foreach(_.logAll(events)) } + def control(event: ControlEvent.Value, message: => String) { delegates.foreach(_.control(event, message)) } + private def dispatch(event: LogEvent) { delegates.foreach(_.log(event)) } +} \ No newline at end of file