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

org.zalando.hutmann.logging.Logger.scala Maven / Gradle / Ivy

There is a newer version: 2.5.4
Show newest version
package org.zalando.hutmann.logging

import java.time.{ Duration, ZonedDateTime }

class Logger(name: String) {
  val logger = play.api.Logger(name)

  protected def createLogString(message: => String, context: Context, file: sourcecode.File, line: sourcecode.Line): String = {
    val codeContext = s"${file.value.substring(file.value.lastIndexOf("/") + 1)}:${line.value}"
    val flowDuration = Duration.between(context.contextInitializationTime, ZonedDateTime.now())

    val contextInfo = context match {
      case RequestContext(requestId, Some(flowId), _, _, _) => s"${flowDuration.toMillis}ms/$codeContext/$flowId"
      case RequestContext(requestId, None, _, _, _)         => s"${flowDuration.toMillis}ms/$codeContext/requestId_$requestId"
      case JobContext(name, Some(flowId), _)                => s"${flowDuration.toMillis}ms/$codeContext/$flowId - $name"
      case JobContext(name, None, _)                        => s"${flowDuration.toMillis}ms/$codeContext/$name"
      case NoContextAvailable                               => s"$codeContext/NoContextAvailable"
    }

    lazy val extraInfo = (for { (key, value) <- context.extraInfo } yield { s"$key=$value" }).mkString(",")
    if (context.extraInfo.isEmpty) {
      s"$message - $contextInfo"
    } else {
      s"$message - $extraInfo - $contextInfo"
    }
  }

  def isTraceEnabled: Boolean = logger.isTraceEnabled
  def isDebugEnabled: Boolean = logger.isDebugEnabled
  def isInfoEnabled: Boolean = logger.isInfoEnabled
  def isWarnEnabled: Boolean = logger.isWarnEnabled
  def isErrorEnabled: Boolean = logger.isErrorEnabled

  def trace(message: => String)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.trace(createLogString(message, context, file, line))
  def trace(message: => String, error: => Throwable)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.trace(createLogString(message, context, file, line), error)

  def debug(message: => String)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.debug(createLogString(message, context, file, line))
  def debug(message: => String, error: => Throwable)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.debug(createLogString(message, context, file, line), error)

  def info(message: => String)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.info(createLogString(message, context, file, line))
  def info(message: => String, error: => Throwable)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.info(createLogString(message, context, file, line), error)

  def warn(message: => String)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.warn(createLogString(message, context, file, line))
  def warn(message: => String, error: => Throwable)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.warn(createLogString(message, context, file, line), error)

  def error(message: => String)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.error(createLogString(message, context, file, line))
  def error(message: => String, error: => Throwable)(implicit context: Context, file: sourcecode.File, line: sourcecode.Line): Unit =
    logger.error(createLogString(message, context, file, line), error)
}

/**
  * Replaces the default play logger. Has access functionality that is
  * equal to the play logger, and uses that logger underneath. However, it
  * additionally puts context information in the log output, like flow ids.
  * It does not implement {{{LoggerLike}}} though, since we change the
  * function declarations.
  *
  * Giving an implicit context is needed - you can't simply omit the
  * implicit parameter. This is for a reason: It lets the compiler check if
  * you have enough information to write a logging statement with flow ids,
  * or not - instead of seeing this on the live system when it is too late.
  * If you really do not want to have a context, you can supply the case object
  * {{{NoContextAvailable}}} - either explicitly, or as an implicit value.
  */
object Logger extends Logger("application") {
  def apply(name: String): Logger = new Logger(name)
  def apply()(implicit name: sourcecode.Name, fullname: sourcecode.FullName): Logger = {
    //use the enclosing class name as logger name. To get it, extract the full name and remove the length of the name plus the extra dot.
    val loggerName = fullname.value.dropRight(name.value.length + 1)
    new Logger(loggerName)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy