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

kamon.trace.Trace.scala Maven / Gradle / Ivy

There is a newer version: 2.7.5
Show newest version
/*
 * Copyright 2013-2021 The Kamon Project 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package kamon
package trace

import java.util.concurrent.atomic.AtomicInteger

/**
  * Holds information shared across all Spans from the same Trace. It might seem like too little information but all in
  * all, a trace is just a bunch of Spans that share the same trace identifier ;).
  */
trait Trace {

  /**
    * Unique identifier for the trace. All Spans related to this trace (in the local and any remote processes) will
    * share the same identifier.
    */
  def id: Identifier

  /**
    * Indicates whether Spans belonging to this Trace should be captured and sent to the Span reporters.
    */
  def samplingDecision: Trace.SamplingDecision

  /**
    * Changes the sampling on this trace to DoNotSample. None of the related Spans finished after the Trace has been
    * dropped will be reported to Span reporters. Ideally, the decision to drop a Trace should be taken as early as
    * possible to avoid situations in which calls to external services are possibly sent out with a Sampled decision
    * and later deciding to drop all the local Spans, which will leave the external service Spans as orphans.
    *
    * Use with caution, in most situations there is no need to manually control the Sampling Decision but rather leave
    * it for the SpanBuilder and Sampler to decide.
    */
  def drop(): Unit

  /**
    * Changes the sampling on this trace to Sample. All of the related Spans finished after the Trace has been marked
    * for keeping will be reported to Span reporters. Ideally, the decision to keep a Trace should be taken as early as
    * possible to avoid situations in which calls to external services are possibly sent out with a NotSampled decision
    * and later deciding to keep all the local Spans, which will produce a partial trace.
    *
    * Use with caution, in most situations there is no need to manually control the Sampling Decision but rather leave
    * it for the SpanBuilder and Sampler to decide.
    */
  def keep(): Unit

  /**
    * Signals that a Span belonging to this trace has failed.
    */
  def spanFailed(): Unit

  /**
    * Returns the number of failed Spans for this trace in this process. This error count does not reflect errors that
    * might have happened on other services participating in the same trace.
    */
  def failedSpansCount(): Int

}

object Trace {

  /**
    * A trace without identifier nor sampling decision. Used to signal that there is no trace information available.
    */
  val Empty: Trace = new MutableTrace(Identifier.Empty, SamplingDecision.Unknown)

  /**
    * Creates a new Trace instance with the provided Id and Sampling Decision.
    */
  def apply(id: Identifier, samplingDecision: SamplingDecision): Trace =
    new MutableTrace(id, samplingDecision)

  /**
    * Creates a new Trace instance with the provided Id and Sampling Decision.
    */
  def create(id: Identifier, samplingDecision: SamplingDecision): Trace =
    new MutableTrace(id, samplingDecision)


  private class MutableTrace(val id: Identifier, initialDecision: Trace.SamplingDecision) extends Trace {
    @volatile private var _samplingDecision = initialDecision
    @volatile private var _failedSpansCount = new AtomicInteger(0)

    override def samplingDecision: SamplingDecision =
      _samplingDecision

    override def drop(): Unit =
      _samplingDecision = SamplingDecision.DoNotSample

    override def keep(): Unit =
      _samplingDecision = SamplingDecision.Sample

    override def spanFailed(): Unit =
      _failedSpansCount.incrementAndGet()

    override def failedSpansCount(): Int =
      _failedSpansCount.get()

    override def toString(): String =
      s"{id=${id.string},samplingDecision=${_samplingDecision}"
  }

  /**
    * A Sampling decision indicates whether Spans belonging to a trace should be captured and sent to the SpanReporters
    * or not.
    */
  sealed abstract class SamplingDecision
  object SamplingDecision {

    /**
      * Indicates that all Spans that belong to a trace should be captured and reported.
      */
    case object Sample extends SamplingDecision {
      override def toString: String = "sample"
    }

    /**
      * Indicates that all Spans that belong to a trace should not be captured nor reported. Note that traces with a
      * "do not sample" decision will still generate Spans that can gather metrics and propagate with the Context, they
      * just don't get sent to the Span reporters.
      */
    case object DoNotSample extends SamplingDecision {
      override def toString: String = "do-not-sample"
    }

    /**
      * Indicates that a sampling decision has not been made yet.
      */
    case object Unknown extends SamplingDecision {
      override def toString: String = "unknown"
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy