Skip to content

Commit

Permalink
Merge pull request #587 from iRevive/trace/span-addlink
Browse files Browse the repository at this point in the history
trace: add `addLink` to `Span`
  • Loading branch information
iRevive committed Apr 9, 2024
2 parents ad8c7c3 + 4155f14 commit 8e75a46
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,42 @@ private[otel4s] trait SpanMacro[F[_]] {
): F[Unit] =
macro SpanMacro.addEventWithTimestampColl

/** Adds a link to the span.
*
* Links are used to link spans in different traces. Used (for example) in
* batching operations, where a single batch handler processes multiple
* requests from different traces or the same trace.
*
* @param spanContext
* the context of the linked span
*
* @param attributes
* the set of attributes to associated with the link
*/
def addLink(
spanContext: SpanContext,
attributes: Attribute[_]*
): F[Unit] =
macro SpanMacro.addLink

/** Adds a link to the span.
*
* Links are used to link spans in different traces. Used (for example) in
* batching operations, where a single batch handler processes multiple
* requests from different traces or the same trace.
*
* @param spanContext
* the context of the linked span
*
* @param attributes
* the set of attributes to associated with the link
*/
def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] =
macro SpanMacro.addLinkColl

/** Records information about the `Throwable` to the span.
*
* @param exception
Expand Down Expand Up @@ -227,6 +263,26 @@ object SpanMacro {
q"if ($meta.isEnabled) $backend.addEvent($name, $attributes) else $meta.unit"
}

def addLink(c: blackbox.Context)(
spanContext: c.Expr[SpanContext],
attributes: c.Expr[Attribute[_]]*
): c.universe.Tree = {
import c.universe._
addLinkColl(c)(spanContext, c.Expr(q"_root_.scala.Seq(..$attributes)"))
}

def addLinkColl(c: blackbox.Context)(
spanContext: c.Expr[SpanContext],
attributes: c.Expr[immutable.Iterable[Attribute[_]]]
): c.universe.Tree = {
import c.universe._

val backend = q"${c.prefix}.backend"
val meta = q"$backend.meta"

q"if ($meta.isEnabled) $backend.addLink($spanContext, $attributes) else $meta.unit"
}

def addEventWithTimestamp(c: blackbox.Context)(
name: c.Expr[String],
timestamp: c.Expr[FiniteDuration],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,42 @@ private[otel4s] trait SpanMacro[F[_]] {
): F[Unit] =
${ SpanMacro.addEvent('self, 'name, 'timestamp, 'attributes) }

/** Adds a link to the span.
*
* Links are used to link spans in different traces. Used (for example) in
* batching operations, where a single batch handler processes multiple
* requests from different traces or the same trace.
*
* @param spanContext
* the context of the linked span
*
* @param attributes
* the set of attributes to associated with the link
*/
inline def addLink(
spanContext: SpanContext,
attributes: Attribute[_]*
): F[Unit] =
${ SpanMacro.addLink('self, 'spanContext, 'attributes) }

/** Adds a link to the span.
*
* Links are used to link spans in different traces. Used (for example) in
* batching operations, where a single batch handler processes multiple
* requests from different traces or the same trace.
*
* @param spanContext
* the context of the linked span
*
* @param attributes
* the set of attributes to associated with the link
*/
inline def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] =
${ SpanMacro.addLink('self, 'spanContext, 'attributes) }

/** Records information about the `Throwable` to the span.
*
* @param exception
Expand Down Expand Up @@ -228,6 +264,17 @@ object SpanMacro {
else $span.backend.meta.unit
}

def addLink[F[_]](
span: Expr[Span[F]],
spanContext: Expr[SpanContext],
attributes: Expr[immutable.Iterable[Attribute[_]]]
)(using Quotes, Type[F]) =
'{
if ($span.backend.meta.isEnabled)
$span.backend.addLink($spanContext, $attributes)
else $span.backend.meta.unit
}

def recordException[F[_]](
span: Expr[Span[F]],
exception: Expr[Throwable],
Expand Down
15 changes: 15 additions & 0 deletions core/trace/src/main/scala/org/typelevel/otel4s/trace/Span.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ object Span {
attributes: immutable.Iterable[Attribute[_]]
): F[Unit]

def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit]

def recordException(
exception: Throwable,
attributes: immutable.Iterable[Attribute[_]]
Expand Down Expand Up @@ -206,6 +211,11 @@ object Span {
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] = unit

def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] = unit

def recordException(
exception: Throwable,
attributes: immutable.Iterable[Attribute[_]]
Expand Down Expand Up @@ -239,6 +249,11 @@ object Span {
attributes: immutable.Iterable[Attribute[_]]
): G[Unit] =
f(backend.addEvent(name, timestamp, attributes))
def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): G[Unit] =
f(backend.addLink(spanContext, attributes))
def recordException(
exception: Throwable,
attributes: immutable.Iterable[Attribute[_]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ private[oteljava] class SpanBackendImpl[F[_]: Sync](
()
}

def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] =
Sync[F].delay {
jSpan.addLink(
SpanContextConversions.toJava(spanContext),
attributes.toJavaAttributes
)
()
}

def setStatus(status: StatusCode): F[Unit] =
Sync[F].delay {
jSpan.setStatus(toJStatus(status))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ private final class SdkSpanBackend[F[_]: Monad: Clock: Console] private (
EventData(name, timestamp, attributes.to(Attributes))
)

def addLink(
context: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): F[Unit] =
updateState("addLink") { s =>
s.copy(links = s.links :+ LinkData(context, attributes.to(Attributes)))
}.void

def recordException(
exception: Throwable,
attributes: immutable.Iterable[Attribute[_]]
Expand Down Expand Up @@ -192,7 +200,7 @@ private final class SdkSpanBackend[F[_]: Monad: Clock: Console] private (
status = state.status,
attributes = state.attributes,
events = state.events,
links = immutableState.links,
links = state.links,
instrumentationScope = immutableState.scopeInfo,
resource = immutableState.resource
)
Expand Down Expand Up @@ -267,14 +275,14 @@ private object SdkSpanBackend {
kind = kind,
parentContext = parentContext,
resource = resource,
links = links,
startTimestamp = startTimestamp
)

val mutableState = MutableState(
name = name,
status = StatusData.Unset,
attributes = attributes,
links = links,
events = Vector.empty,
endTimestamp = None
)
Expand All @@ -293,7 +301,6 @@ private object SdkSpanBackend {
kind: SpanKind,
parentContext: Option[SpanContext],
resource: TelemetryResource,
links: Vector[LinkData],
startTimestamp: FiniteDuration
)

Expand All @@ -304,6 +311,7 @@ private object SdkSpanBackend {
status: StatusData,
attributes: Attributes,
events: Vector[EventData],
links: Vector[LinkData],
endTimestamp: Option[FiniteDuration]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ class SdkSpanBackendSuite extends CatsEffectSuite with ScalaCheckEffectSuite {
}
}

test(".addLink(:SpanContext, :Attribute[_]*)") {
PropF.forAllF { (spanContext: SpanContext, attrs: Attributes) =>
val link = LinkData(spanContext, attrs)

TestControl.executeEmbed {
for {
span <- start()
_ <- assertIO(span.toSpanData.map(_.links), Vector.empty)
_ <- span.addLink(spanContext, attrs)
_ <- assertIO(span.toSpanData.map(_.links), Vector(link))
} yield ()
}
}
}

test(".updateName(:String)") {
PropF.forAllF { (name: String, nextName: String) =>
for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ class SimpleSpanProcessorSuite
): IO[Unit] =
noopBackend.addEvent(name, timestamp, attributes)

def addLink(
spanContext: SpanContext,
attributes: immutable.Iterable[Attribute[_]]
): IO[Unit] =
noopBackend.addLink(spanContext, attributes)

def recordException(
exception: Throwable,
attributes: immutable.Iterable[Attribute[_]]
Expand Down

0 comments on commit 8e75a46

Please sign in to comment.