All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scribe.throwable.Trace.scala Maven / Gradle / Ivy

The newest version!
package scribe.throwable

import scribe.message.LoggableMessage
import scribe.output.{CompositeOutput, EmptyOutput, LogOutput, TextOutput}

import scala.annotation.tailrec

case class Trace(className: String,
                 message: Option[String],
                 elements: List[TraceElement],
                 cause: Option[Trace])

case class TraceLoggableMessage(throwable: Throwable) extends LoggableMessage {
  override lazy val value: Trace = Trace.throwable2Trace(throwable)

  override lazy val logOutput: LogOutput = Trace.toLogOutput(EmptyOutput, value)
}

object Trace {
  private val NativeMethod: Int = -2

  def throwable2Trace(throwable: Throwable): Trace = {
    val elements = throwable.getStackTrace.toList.map { e =>
      TraceElement(e.getClassName, e.getFileName, e.getMethodName, e.getLineNumber)
    }
    val message = throwable.getLocalizedMessage match {
      case null | "" => None
      case m => Some(m)
    }
    Trace(throwable.getClass.getName, message, elements, Option(throwable.getCause).map(throwable2Trace))
  }

  @tailrec
  final def toLogOutput(message: LogOutput,
                        trace: Trace,
                        primaryCause: Boolean = true,
                        b: StringBuilder = new StringBuilder): LogOutput = {
    if (!primaryCause) {
      b.append("Caused by: ")
    }
    b.append(trace.className)
    trace.message.foreach { message =>
      b.append(": ")
      b.append(message)
    }
    b.append(scribe.lineSeparator)
    writeStackTrace(b, trace.elements)
    trace.cause match {
      case Some(cause) => toLogOutput(message, cause, primaryCause = false, b = b)
      case None =>
        val output = new TextOutput(b.toString())
        if (message == EmptyOutput) {
          output
        } else {
          new CompositeOutput(List(message, new TextOutput(scribe.lineSeparator), output))
        }
    }
  }

  @tailrec
  private def writeStackTrace(b: StringBuilder, elements: List[TraceElement]): Unit = {
    elements.headOption match {
      case None => // No more elements
      case Some(head) =>
        b.append("\tat ")
        b.append(head.`class`)
        b.append('.')
        b.append(head.method)
        b.append('(')
        if (head.line == NativeMethod) {
          b.append("Native Method")
        } else {
          b.append(head.fileName)
          if (head.line > 0) {
            b.append(':')
            b.append(head.line)
          }
        }
        b.append(')')
        b.append(scribe.lineSeparator)
        writeStackTrace(b, elements.tail)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy