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

scribe.mdc.MDC.scala Maven / Gradle / Ivy

There is a newer version: 3.15.3
Show newest version
package scribe.mdc

import perfolation.double2Implicits
import scribe.util.Time

import scala.language.implicitConversions

object MDC {
  /**
   * Global MDC instance. By default, all instances of MDC inherit from this.
   */
  lazy val global: MDC = creator(None)

  /**
   * The MDCManager responsible for retrieving an MDC instance for the context. By default this uses MDCThreadLocal but
   * can replaced with something more advanced.
   */
  var manager: MDCManager = MDCThreadLocal

  /**
   * The function to create MDC instances. Receives the parent and creates a new MDC instance. By default, this will use
   * MDCMap, but this can be replaced to provide a different implementation.
   */
  var creator: Option[MDC] => MDC = parent => new MDCMap(parent)

  def apply[Return](f: MDC => Return): Return = {
    val previous = manager.instance
    val mdc = new MDCMap(Some(previous))
    try {
      manager.instance = mdc
      f(mdc)
    } finally {
      manager.instance = previous
    }
  }

  /**
   * Convenience implicit to get the current instance of MDC from the manager
   */
  implicit def instance: MDC = manager.instance

  /**
   * Sets the instance for the current context
   */
  def set(mdc: MDC): Unit = manager.instance = mdc

  /**
   * Sets the instance for the current context for the duration of the function `f`.
   */
  def contextualize[Return](mdc: MDC)(f: => Return): Return = {
    val previous = manager.instance
    set(mdc)
    try {
      f
    } finally {
      set(previous)
    }
  }

  def map: Map[String, () => Any] = instance.map
  def get(key: String): Option[Any] = instance.get(key).map(_())
  def getOrElse(key: String, default: => Any): Any= get(key).getOrElse(default)
  def update(key: String, value: => Any): Option[Any] = instance(key) = value
  def set(key: String, value: Option[Any]): Option[Any] = instance.set(key, value)
  def context[Return](values: (String, MDCValue)*)(f: => Return): Return = instance.context(values: _*)(f)
  def elapsed(key: String = "elapsed", timeFunction: () => Long = Time.function): Unit = instance.elapsed(key, timeFunction)
  def remove(key: String): Option[Any] = instance.remove(key)
  def contains(key: String): Boolean = instance.contains(key)
  def clear(): Unit = instance.clear()
}

trait MDC {
  /**
   * Retrieves the functional map
   */
  def map: Map[String, () => Any]

  /**
   * Gets the value function for this key if set
   */
  def get(key: String): Option[() => Any]

  /**
   * Updates the value for the specified key. The `context` method should be preferred to avoid leaving MDC values set
   * forever. Returns the previous value for this key.
   */
  def update(key: String, value: => Any): Option[Any]

  /**
   * Sets the value for the specified key. This method differs from `update` by taking an `Option` that will remove the
   * key if set to `None`. Returns the previous value for this key.
   */
  def set(key: String, value: Option[Any]): Option[Any]

  /**
   * Contextualizes setting multiple values similar to `update`, but returns them to their previous value upon
   * completion of the context function `f`.
   */
  def context[Return](values: (String, MDCValue)*)(f: => Return): Return

  /**
   * Applies an elapsed function as an MDC value. This represents a dynamically changing value of time elapsed since the
   * this was set.
   */
  def elapsed(key: String, timeFunction: () => Long = Time.function): Unit = {
    val start = timeFunction()
    update(key, s"${((timeFunction() - start) / 1000.0).f()}s")
  }

  /**
   * Removes a key from this MDC instance
   */
  def remove(key: String): Option[Any]

  /**
   * True if this MDC contains the specified key
   */
  def contains(key: String): Boolean

  /**
   * Clears all values from this MDC
   */
  def clear(): Unit
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy