Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for span suppression and coalescing, simplify span creation API via builder pattern #665

Merged
merged 8 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import com.typesafe.tools.mima.core._

ThisBuild / tlBaseVersion := "0.2"
ThisBuild / tlBaseVersion := "0.3"

val scala212Version = "2.12.17"
val scala213Version = "2.13.10"
Expand Down
88 changes: 70 additions & 18 deletions modules/core/shared/src/main/scala/Span.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ trait Span[F[_]] {
*/
def kernel: F[Kernel]

/** Resource that yields a child span with the given name. */
def span(name: String): Resource[F, Span[F]]

/** Resource that yields a child span of both this span and the given kernel. */
def span(name: String, kernel: Kernel): Resource[F, Span[F]]
/** Resource that yields a child span of this span. */
def span(name: String, options: Span.Options = Span.Options.Defaults): Resource[F, Span[F]]

/** A unique ID for the trace of this span, if available.
* This can be useful to include in error messages for example, so you can quickly find the associated trace.
Expand Down Expand Up @@ -75,8 +72,8 @@ trait Span[F[_]] {
override def log(fields: (String, TraceValue)*) =
f(outer.log(fields: _*))

override def span(name: String): Resource[G, Span[G]] = outer
.span(name)
override def span(name: String, options: Span.Options): Resource[G, Span[G]] = outer
.span(name, options)
.map(_.mapK(f))
.mapK(f)

Expand All @@ -85,18 +82,26 @@ trait Span[F[_]] {
override def traceId: G[Option[String]] = f(outer.traceId)

override def traceUri: G[Option[URI]] = f(outer.traceUri)

/** Create resource with new span and add current span and kernel to parents of new span */
override def span(name: String, kernel: Kernel): Resource[G, Span[G]] = outer
.span(name, kernel)
.map(_.mapK(f))
.mapK(f)
}
}
}

object Span {

abstract class Default[F[_]: Applicative] extends Span[F] {
protected val spanCreationPolicy: Options.SpanCreationPolicy

def span(name: String, options: Options): Resource[F, Span[F]] =
spanCreationPolicy match {
case Options.SpanCreationPolicy.Suppress => Resource.pure(Span.noop[F])
case Options.SpanCreationPolicy.Coalesce => Resource.pure(this)
case Options.SpanCreationPolicy.Default => makeSpan(name, options)
}

/** Like `span` but always creates a child span -- i.e., `options.spanCreationPolicy` is ignored. */
def makeSpan(name: String, options: Options): Resource[F, Span[F]]
}

/** Ensure that Fields mixin data is added to a span when an error is raised.
*/
def putErrorFields[F[_]: Applicative](span: Resource[F, Span[F]]): Resource[F, Span[F]] =
Expand Down Expand Up @@ -130,14 +135,13 @@ object Span {
}

private class NoopSpan[F[_]: Applicative] extends EphemeralSpan[F] {
def span(name: String): Resource[F, Span[F]] = Resource.pure(this)
override def span(name: String, kernel: Kernel): Resource[F, Span[F]] = Resource.pure(this)
override def span(name: String, options: Span.Options): Resource[F, Span[F]] =
Resource.pure(this)
}

private class RootsSpan[F[_]: Applicative](ep: EntryPoint[F]) extends EphemeralSpan[F] {
def span(name: String): Resource[F, Span[F]] = ep.root(name)
override def span(name: String, kernel: Kernel): Resource[F, Span[F]] =
ep.continueOrElseRoot(name, kernel)
override def span(name: String, options: Span.Options): Resource[F, Span[F]] =
options.parentKernel.fold(ep.root(name))(ep.continueOrElseRoot(name, _))
}

private def resolve[F[_]](span: Span[F]): Kleisli[F, Span[F], *] ~> F =
Expand All @@ -154,4 +158,52 @@ object Span {
def rootTracing[F[_]: Applicative](ep: EntryPoint[F]): Kleisli[F, Span[F], *] ~> F = resolve(
makeRoots(ep)
)

/** Options for creating a new span. */
sealed trait Options {

/** Optional parent kernel for the child span, in addition to the parent span.
*
* Some backends do not support multiple parents, in which case the
* parent span is preferred and this parent kernel is ignored.
*/
def parentKernel: Option[Kernel]

/** Specifies how additional span creation requests are handled on the new span. */
def spanCreationPolicy: Options.SpanCreationPolicy

def withParentKernel(kernel: Kernel): Options
def withoutParentKernel: Options
def withSpanCreationPolicy(p: Options.SpanCreationPolicy): Options
}

object Options {
sealed trait SpanCreationPolicy
object SpanCreationPolicy {

/** Span creation behaves normally. */
case object Default extends SpanCreationPolicy

/** Requests for span creation are ignored and any information provided to the returned span are also ignored. */
case object Suppress extends SpanCreationPolicy

/** Requests for span creation are ignored but information provided to the returned span are attached to the original span. */
case object Coalesce extends SpanCreationPolicy
}

private case class OptionsImpl(
parentKernel: Option[Kernel],
spanCreationPolicy: SpanCreationPolicy
) extends Options {
def withParentKernel(kernel: Kernel): Options = OptionsImpl(Some(kernel), spanCreationPolicy)
def withoutParentKernel: Options = OptionsImpl(None, spanCreationPolicy)
def withSpanCreationPolicy(p: SpanCreationPolicy): Options = OptionsImpl(parentKernel, p)
}

val Defaults: Options = OptionsImpl(None, SpanCreationPolicy.Default)
val Suppress: Options = Defaults.withSpanCreationPolicy(SpanCreationPolicy.Suppress)
val Coalesce: Options = Defaults.withSpanCreationPolicy(SpanCreationPolicy.Coalesce)

def parentKernel(kernel: Kernel): Options = Defaults.withParentKernel(kernel)
}
}
Loading