first round of logger cleanup/migration

This commit is contained in:
Mark Harrah 2010-06-10 21:26:27 -04:00
parent 1584f01de8
commit e02adb0694
9 changed files with 142 additions and 34 deletions

View File

@ -1,15 +1,15 @@
/* sbt -- Simple Build Tool /* 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.*/ /** 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 private var level: Level.Value = Level.Info
def getLevel = level def getLevel = level
def setLevel(newLevel: Level.Value) { level = newLevel } def setLevel(newLevel: Level.Value) { level = newLevel }
def enableTrace(flag: Boolean) { traceEnabledVar = flag } def setTrace(level: Int) { traceEnabledVar = level }
def traceEnabled = traceEnabledVar def getTrace = traceEnabledVar
} }

View File

@ -1,8 +1,9 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009, 2010 Mark Harrah
*/ */
package xsbt package xsbt
import sbt.{AbstractLogger, ControlEvent, Level, Log, LogEvent, SetLevel, SetTrace, Success, Trace}
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
/** A logger that can buffer the logging done on it and then can flush the buffer /** 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. * 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] val buffer = new ListBuffer[LogEvent]
private[this] var recording = false private[this] var recording = false
@ -54,10 +55,10 @@ class BufferedLogger(delegate: Logger) extends Logger
} }
def getLevel = delegate.getLevel def getLevel = delegate.getLevel
def traceEnabled = delegate.traceEnabled def traceEnabled = delegate.traceEnabled
def enableTrace(flag: Boolean) def setTrace(level: Int)
{ {
buffer += new SetTrace(flag) buffer += new SetTrace(level)
delegate.enableTrace(flag) delegate.setTrace(level)
} }
def trace(t: => Throwable): Unit = def trace(t: => Throwable): Unit =
@ -73,9 +74,9 @@ class BufferedLogger(delegate: Logger) extends Logger
delegate.logAll(events) delegate.logAll(events)
def control(event: ControlEvent.Value, message: => String): Unit = def control(event: ControlEvent.Value, message: => String): Unit =
doBufferable(Level.Info, new ControlEvent(event, message), _.control(event, message)) 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) 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(condition)
{ {
if(recording) if(recording)

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009, 2010 Mark Harrah
*/ */
package xsbt package sbt
object ConsoleLogger object ConsoleLogger
{ {
@ -17,10 +17,12 @@ object ConsoleLogger
} }
/** A logger that logs to the console. On supported systems, the level labels are /** 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 class ConsoleLogger extends BasicLogger
{ {
import ConsoleLogger.formatEnabled override def ansiCodesSupported = ConsoleLogger.formatEnabled
def messageColor(level: Level.Value) = Console.RESET def messageColor(level: Level.Value) = Console.RESET
def labelColor(level: Level.Value) = def labelColor(level: Level.Value) =
level match level match
@ -39,8 +41,9 @@ class ConsoleLogger extends BasicLogger
def trace(t: => Throwable): Unit = def trace(t: => Throwable): Unit =
System.out.synchronized System.out.synchronized
{ {
if(traceEnabled) val traceLevel = getTrace
t.printStackTrace if(traceLevel >= 0)
System.out.synchronized { System.out.print(StackTrace.trimmed(t, traceLevel)) }
} }
def log(level: Level.Value, message: => String) def log(level: Level.Value, message: => String)
{ {
@ -49,7 +52,7 @@ class ConsoleLogger extends BasicLogger
} }
private def setColor(color: String) private def setColor(color: String)
{ {
if(formatEnabled) if(ansiCodesSupported)
System.out.synchronized { System.out.print(color) } System.out.synchronized { System.out.print(color) }
} }
private def log(labelColor: String, label: String, messageColor: String, message: String): Unit = private def log(labelColor: String, label: String, messageColor: String, message: String): Unit =

View File

@ -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)
}

View File

@ -1,11 +1,11 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
/** An enumeration defining the levels available for logging. A level includes all of the levels /** 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).*/ * 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 Debug = Value(1, "debug")
val Info = Value(2, "info") val Info = Value(2, "info")
@ -16,10 +16,8 @@ object Level extends Enumeration with NotNull
* label is also defined here. */ * label is also defined here. */
val SuccessLabel = "success" 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. */ /** 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. */ /** 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)
} }

View File

@ -1,14 +1,14 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
sealed trait LogEvent extends NotNull sealed trait LogEvent extends NotNull
final class Success(val msg: String) extends LogEvent final class Success(val msg: String) extends LogEvent
final class Log(val level: Level.Value, 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 Trace(val exception: Throwable) extends LogEvent
final class SetLevel(val newLevel: Level.Value) 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 final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent
object ControlEvent extends Enumeration object ControlEvent extends Enumeration

View File

@ -1,18 +1,22 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
import xsbti.{Logger => xLogger, F0} import xsbti.{Logger => xLogger, F0}
abstract class Logger extends xLogger with NotNull
abstract class AbstractLogger extends xLogger with NotNull
{ {
def getLevel: Level.Value def getLevel: Level.Value
def setLevel(newLevel: Level.Value) def setLevel(newLevel: Level.Value)
def enableTrace(flag: Boolean) def setTrace(flag: Int)
def traceEnabled: Boolean def getTrace: Int
final def traceEnabled = getTrace >= 0
def ansiCodesSupported = false
def atLevel(level: Level.Value) = level.id >= getLevel.id def atLevel(level: Level.Value) = level.id >= getLevel.id
def trace(t: => Throwable): Unit 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 debug(message: => String): Unit = log(Level.Debug, message)
final def info(message: => String): Unit = log(Level.Info, message) final def info(message: => String): Unit = log(Level.Info, message)
final def warn(message: => String): Unit = log(Level.Warn, 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 l: Log => log(l.level, l.msg)
case t: Trace => trace(t.exception) case t: Trace => trace(t.exception)
case setL: SetLevel => setLevel(setL.newLevel) 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) case c: ControlEvent => control(c.event, c.msg)
} }
} }

View File

@ -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)
}

View File

@ -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)) }
}