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

com.ossuminc.riddl.utils.Logging.scala Maven / Gradle / Ivy

/*
 * Copyright 2019 Ossum, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package com.ossuminc.riddl.utils

import scala.annotation.unused
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.io.AnsiColor.*
import scala.scalajs.js.annotation._

@JSExportTopLevel("Logger")
object Logging {
  sealed trait Lvl {
    override def toString: String = this.getClass.getSimpleName.dropRight(1).toLowerCase
  }

  case object Severe extends Lvl
  case object Error extends Lvl
  case object Warning extends Lvl
  case object Usage extends Lvl
  case object Style extends Lvl
  case object Missing extends Lvl
  case object Info extends Lvl

  val nl: String = "\n"
}

trait Logger {
  import Logging.*

  protected def withHighlighting: Boolean = true

  final def severe(s: => String): Unit = { write(Severe, s) }
  final def severe(s: => String, xcptn: Throwable): Unit = {
    val message =
      s"""$s: $xcptn
         |${ExceptionUtils.getRootCauseStackTrace(xcptn).mkString("\n")}
         |""".stripMargin
    write(Severe, message)
  }

  final def error(s: => String): Unit = { write(Error, s) }

  final def warn(s: => String): Unit = { write(Warning, s) }

  final def usage(s: => String): Unit = { write(Usage, s) }
  final def style(s: => String): Unit = { write(Style, s) }
  final def missing(s: => String): Unit = { write(Missing, s) }

  final def info(s: => String): Unit = { write(Info, s) }

  private var nSevere = 0
  private var nError = 0
  private var nMissing = 0
  private var nStyle = 0
  private var nUsage = 0
  private var nWarning = 0
  private var nInfo = 0

  protected def highlight(level: Lvl, s: String): String = {
    if !withHighlighting then s"[$level] $s"
    else
      val prefix = level match {
        case Logging.Severe  => s"$RED_B$BLACK"
        case Logging.Error   => s"$RED"
        case Logging.Warning => s"$YELLOW"
        case Logging.Usage   => s"$GREEN"
        case Logging.Style   => s"$GREEN"
        case Logging.Missing => s"$GREEN"
        case Logging.Info    => s"$BLUE"
      }
      val lines = s.split(nl)
      val head = s"$prefix$BOLD[$level] ${lines.head}$RESET"
      val tail = lines.tail.mkString(nl)
      if tail.nonEmpty then head + s"$nl$prefix$tail$RESET"
      else head
  }

  protected def write(level: Lvl, @unused s: String): Unit

  protected def count(level: Lvl): Unit = {
    level match {
      case Severe  => nSevere += 1
      case Error   => nError += 1
      case Warning => nWarning += 1
      case Style   => nStyle += 1
      case Usage   => nUsage += 1
      case Missing => nMissing += 1
      case Info    => nInfo += 1
    }
  }

  def summary: String = {
    s"""Severe Errors: $nSevere
       |Normal Errors: $nError
       |     Warnings: $nWarning
       |        Usage: $nUsage
       |        Style: $nStyle
       |     Misasing: $nMissing
       |         Info: $nInfo
       |""".stripMargin
  }
}

case class SysLogger(override val withHighlighting: Boolean = true) extends Logger {
  override def write(level: Logging.Lvl, s: String): Unit = {
    super.count(level)
    System.out.println(highlight(level, s))
  }
}

@JSExportTopLevel("StringLogger")
case class StringLogger(capacity: Int = 512 * 2, override val withHighlighting: Boolean = true)
    extends Logger {
  private val stringBuilder = new mutable.StringBuilder(capacity)

  override def write(level: Logging.Lvl, s: String): Unit = {
    super.count(level)
    stringBuilder.append(highlight(level, s)).append("\n")
  }

  override def toString: String = stringBuilder.toString()
}

/** A Logger which captures logged lines into an in-memory buffer, useful for testing purposes.
  */
@JSExportTopLevel("InMemoryLogger")
case class InMemoryLogger(override val withHighlighting: Boolean = false) extends Logger {
  case class Line(level: Logging.Lvl, msg: String)

  private val buffer = ArrayBuffer[Line]()

  /** Returns an Iterator of all lines logged to this logger, oldest-first */
  def lines(): Iterator[Line] = buffer.iterator

  def write(level: Logging.Lvl, s: String): Unit = {
    super.count(level)
    buffer += Line(level, s)
  }
}

@JSExportTopLevel("CallBackLogger")
case class CallBackLogger(callback: (Logging.Lvl, String) => Unit) extends Logger {
  override def write(level: Logging.Lvl, s: String): Unit = {
    super.count(level)
    callback(level, s)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy