aboutsummaryrefslogblamecommitdiff
path: root/kamon-core/src/main/scala/kamon/context/Context.scala
blob: f7c7838894d48b2243e13039d5bed7b9dcee2e36 (plain) (tree)


















































































































































                                                                                                        
package kamon.context

class Context private (private val keys: Map[Key[_], Any]) {
  def get[T](key: Key[T]): T =
    keys.get(key).getOrElse(key.emptyValue).asInstanceOf[T]

  def withKey[T](key: Key[T], value: T): Context =
    new Context(keys.updated(key, value))
}

object Context {
  val Empty = new Context(Map.empty)

  def apply(): Context = Empty
  def create(): Context = Empty
}


trait Key[T] {
  def name: String
  def emptyValue: T
  def broadcast: Boolean
}

object Key {

  def local[T](name: String, emptyValue: T): Key[T] =
    new Default[T](name, emptyValue, false)

  def broadcast[T](name: String, emptyValue: T): Key[T] =
    new Default[T](name, emptyValue, true)


  private class Default[T](val name: String, val emptyValue: T, val broadcast: Boolean) extends Key[T] {
    override def hashCode(): Int =
      name.hashCode

    override def equals(that: Any): Boolean =
      that.isInstanceOf[Default[_]] && that.asInstanceOf[Default[_]].name == this.name
  }
}

trait Storage {
  def current(): Context
  def store(context: Context): Scope

  trait Scope {
    def context: Context
    def close(): Unit
  }
}

object Storage {

  class ThreadLocal extends Storage {
    private val tls = new java.lang.ThreadLocal[Context]() {
      override def initialValue(): Context = Context.Empty
    }

    override def current(): Context =
      tls.get()

    override def store(context: Context): Scope = {
      val newContext = context
      val previousContext = tls.get()
      tls.set(newContext)

      new Scope {
        override def context: Context = newContext
        override def close(): Unit = tls.set(previousContext)
      }
    }
  }
}

trait KeyCodec[T] {
  def encode(context: Context): T
  def decode(carrier: T, context: Context): Context
}

/*
object Example {
  // this is defined somewhere statically, only once.
  val User = Key.local[Option[User]]("user", None)
  val Client = Key.local[Option[User]]("client", null)
  val Span = Key.broadcast[Span]("span", EmptySpan)
  val storage = Kamon.contextStorage // or something similar.

  storage.get(Span) // returns a Span instance or EmptySpan.
  storage.get(User) // Returns Option[User] or None if not set.
  storage.get(Client) // Returns Option[Client] or null if not set.

  // Context Propagation works the very same way as before.

  val scope = storage.store(context)
  // do something here
  scope.close()

  // Configuration for codecs would be handled sort of like this:

  //  kamon.context.propagation {
  //    http-header-codecs {
  //      "span" = kamon.trace.propagation.B3
  //    }
  //
  //    binary-codecs {
  //      "span" = kamon.trace.propagation.Binary
  //    }
  //  }





}*/



/*





class Context(private val keys: Map[Key[_], Any]) {
  




}

object Context {


}

sealed trait Key[T] {
  def name: String
}

object Key {

  def local[T](name: String): Key[T] = Local(name)

  case class Local[T](name: String) extends Key[T]
}*/