Second try at printing message when stack trace suppressed.

Problems:

  1. Without a message, users don't find 'last'
  2. Showing a message for every error clutters output.

This tries to address these issues by:

1. Only showing the message when other feedback has not been provided and
   'last' would not usually be helpful.  This will require ongoing tweaking.
   For now, all commands except 'compile' display the message.  'update' could
   omit the message as well, but perhaps knowing about 'last' might be
   useful there.

2. Including the exact command to show the output:
    last test:compile
   and not just
    last <task>

3. Highlighting the command in blue for visibility as an experiment.

Review by @ijuma and @retronym, please.
This commit is contained in:
Mark Harrah 2012-05-19 18:20:19 -04:00
parent eec347e2dd
commit 1f9433f175
3 changed files with 34 additions and 21 deletions

View File

@ -7,8 +7,12 @@ final class MessageOnlyException(override val toString: String) extends RuntimeE
/** A dummy exception for the top-level exception handler to know that an exception
* has been handled, but is being passed further up to indicate general failure. */
final class AlreadyHandledException extends RuntimeException
final class AlreadyHandledException(val underlying: Throwable) extends RuntimeException
/** A marker trait for a top-level exception handler to know that this exception
* doesn't make sense to display. */
trait UnprintableException extends Throwable
trait UnprintableException extends Throwable
/** A marker trait that refines UnprintableException to indicate to a top-level exception handler
* that the code throwing this exception has already provided feedback to the user about the error condition. */
trait FeedbackProvidedException extends UnprintableException

View File

@ -42,15 +42,16 @@ object ConsoleLogger
} catch {
case e: Exception => !isWindows
}
val noSuppressedMessage = (_: SuppressedTraceContext) => None
private[this] def os = System.getProperty("os.name")
private[this] def isWindows = os.toLowerCase.indexOf("windows") >= 0
def apply(): ConsoleLogger = apply(systemOut)
def apply(out: PrintStream): ConsoleLogger = apply(printStreamOut(out))
def apply(out: PrintWriter): ConsoleLogger = apply(printWriterOut(out))
def apply(out: ConsoleOut, ansiCodesSupported: Boolean = formatEnabled, useColor: Boolean = formatEnabled): ConsoleLogger =
new ConsoleLogger(out, ansiCodesSupported, useColor)
def apply(out: ConsoleOut = systemOut, ansiCodesSupported: Boolean = formatEnabled,
useColor: Boolean = formatEnabled, suppressedMessage: SuppressedTraceContext => Option[String] = noSuppressedMessage): ConsoleLogger =
new ConsoleLogger(out, ansiCodesSupported, useColor, suppressedMessage)
private[this] val EscapeSequence = (27.toChar + "[^@-~]*[@-~]").r
def stripEscapeSequences(s: String): String =
@ -61,7 +62,7 @@ object ConsoleLogger
* colored.
*
* This logger is not thread-safe.*/
class ConsoleLogger private[ConsoleLogger](val out: ConsoleOut, override val ansiCodesSupported: Boolean, val useColor: Boolean) extends BasicLogger
class ConsoleLogger private[ConsoleLogger](val out: ConsoleOut, override val ansiCodesSupported: Boolean, val useColor: Boolean, val suppressedMessage: SuppressedTraceContext => Option[String]) extends BasicLogger
{
import scala.Console.{BLUE, GREEN, RED, RESET, YELLOW}
def messageColor(level: Level.Value) = RESET
@ -85,6 +86,9 @@ class ConsoleLogger private[ConsoleLogger](val out: ConsoleOut, override val ans
val traceLevel = getTrace
if(traceLevel >= 0)
out.print(StackTrace.trimmed(t, traceLevel))
if(traceLevel <= 2)
for(msg <- suppressedMessage(new SuppressedTraceContext(traceLevel, ansiCodesSupported && useColor)))
printLabeledLine(labelColor(Level.Error), "trace", messageColor(Level.Error), msg)
}
def log(level: Level.Value, message: => String)
{
@ -102,24 +106,27 @@ class ConsoleLogger private[ConsoleLogger](val out: ConsoleOut, override val ans
out.lockObject.synchronized
{
for(line <- message.split("""\n"""))
{
reset()
out.print("[")
setColor(labelColor)
out.print(label)
reset()
out.print("] ")
setColor(messageColor)
out.print(line)
reset()
out.println()
}
printLabeledLine(labelColor, label, messageColor, line)
}
private def printLabeledLine(labelColor: String, label: String, messageColor: String, line: String): Unit =
{
reset()
out.print("[")
setColor(labelColor)
out.print(label)
reset()
out.print("] ")
setColor(messageColor)
out.print(line)
reset()
out.println()
}
def logAll(events: Seq[LogEvent]) = out.lockObject.synchronized { events.foreach(log) }
def control(event: ControlEvent.Value, message: => String)
{ log(labelColor(Level.Info), Level.Info.toString, BLUE, message) }
}
final class SuppressedTraceContext(val traceLevel: Int, val useColor: Boolean)
sealed trait ConsoleOut
{
val lockObject: AnyRef

View File

@ -25,12 +25,14 @@ object MainLogging
}
def defaultMultiConfig(backing: AbstractLogger): MultiLoggerConfig =
new MultiLoggerConfig(defaultScreen, backing, Nil, Level.Info, Level.Debug, -1, Int.MaxValue)
new MultiLoggerConfig(defaultScreen(ConsoleLogger.noSuppressedMessage), backing, Nil, Level.Info, Level.Debug, -1, Int.MaxValue)
def defaultScreen: AbstractLogger = ConsoleLogger()
def defaultScreen(): AbstractLogger = ConsoleLogger()
def defaultScreen(suppressedMessage: SuppressedTraceContext => Option[String]): AbstractLogger = ConsoleLogger(suppressedMessage = suppressedMessage)
def defaultBacked(useColor: Boolean = ConsoleLogger.formatEnabled): PrintWriter => ConsoleLogger =
to => ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = useColor) // TODO: should probably filter ANSI codes when useColor=false
}
final case class MultiLoggerConfig(console: AbstractLogger, backed: AbstractLogger, extra: List[AbstractLogger], screenLevel: Level.Value, backingLevel: Level.Value, screenTrace: Int, backingTrace: Int)
final case class MultiLoggerConfig(console: AbstractLogger, backed: AbstractLogger, extra: List[AbstractLogger],
screenLevel: Level.Value, backingLevel: Level.Value, screenTrace: Int, backingTrace: Int)