Skip to content

Commit 4af5f93

Browse files
committed
add ListValue to TraceValue ADT
1 parent fcc2c92 commit 4af5f93

11 files changed

Lines changed: 35 additions & 8 deletions

File tree

modules/core/shared/src/main/scala/TraceValue.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
package natchez
66

7+
import cats.*
8+
import cats.syntax.all.*
9+
710
sealed trait TraceValue extends Product with Serializable {
811
def value: Any
912
}
@@ -13,6 +16,7 @@ object TraceValue {
1316
case class StringValue(value: String) extends TraceValue
1417
case class BooleanValue(value: Boolean) extends TraceValue
1518
case class NumberValue(value: Number) extends TraceValue
19+
case class ListValue(value: List[TraceValue]) extends TraceValue
1620

1721
implicit def viaTraceableValue[A: TraceableValue](a: A): TraceValue =
1822
TraceableValue[A].toTraceValue(a)
@@ -57,4 +61,7 @@ object TraceableValue {
5761
implicit val longToTraceValue: TraceableValue[Long] = TraceValue.NumberValue(_)
5862
implicit val doubleToTraceValue: TraceableValue[Double] = TraceValue.NumberValue(_)
5963
implicit val floatToTraceValue: TraceableValue[Float] = TraceValue.NumberValue(_)
64+
65+
implicit def foldableToTraceValue[F[_]: Foldable, A: TraceableValue]: TraceableValue[F[A]] =
66+
fa => TraceValue.ListValue(fa.toList.map(TraceableValue[A].toTraceValue))
6067
}

modules/datadog/src/main/scala/DDSpan.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import cats.syntax.all._
1313
import io.opentracing.log.Fields
1414
import io.opentracing.propagation.{Format, TextMapAdapter}
1515
import io.opentracing.tag.Tags
16-
import natchez.TraceValue.{BooleanValue, NumberValue, StringValue}
16+
import natchez.TraceValue._
1717
import _root_.datadog.trace.api.DDTags
1818
import natchez.Span.Options
1919
import natchez.datadog.DDTracer.{addLink, addSpanKind}
@@ -46,6 +46,7 @@ final case class DDSpan[F[_]: Sync](
4646
case (str, StringValue(value)) => Sync[F].delay(span.setTag(str, value))
4747
case (str, NumberValue(value)) => Sync[F].delay(span.setTag(str, value))
4848
case (str, BooleanValue(value)) => Sync[F].delay(span.setTag(str, value))
49+
case (str, ListValue(v)) => Sync[F].delay(span.setTag(str, v.map(_.toString).mkString(", ")))
4950
}
5051

5152
override def log(fields: (String, TraceValue)*): F[Unit] = {

modules/jaeger/src/main/scala/JaegerSpan.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ private[jaeger] final case class JaegerSpan[F[_]: Sync](
4343
case (k, StringValue(v)) => Sync[F].delay(span.setTag(k, v))
4444
case (k, NumberValue(v)) => Sync[F].delay(span.setTag(k, v))
4545
case (k, BooleanValue(v)) => Sync[F].delay(span.setTag(k, v))
46+
case (k, ListValue(v)) => Sync[F].delay(span.setTag(k, v.map(_.toString).mkString(", ")))
4647
}
4748

4849
override def attachError(err: Throwable, fields: (String, TraceValue)*): F[Unit] =

modules/lightstep/src/main/scala/LightstepSpan.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ private[lightstep] final case class LightstepSpan[F[_]: Sync](
3939
case (k, StringValue(v)) => Sync[F].delay(span.setTag(k, v))
4040
case (k, NumberValue(v)) => Sync[F].delay(span.setTag(k, v))
4141
case (k, BooleanValue(v)) => Sync[F].delay(span.setTag(k, v))
42+
case (k, ListValue(v)) => Sync[F].delay(span.setTag(k, v.map(_.toString).mkString(", ")))
4243
}
4344

4445
override def attachError(err: Throwable, fields: (String, TraceValue)*): F[Unit] =

modules/log-odin/src/main/scala/LogSpan.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ private[logodin] final case class LogSpan[F[_]: Sync: Logger](
123123

124124
private[logodin] object LogSpan {
125125

126-
implicit val EncodeTraceValue: Encoder[TraceValue] =
126+
implicit lazy val EncodeTraceValue: Encoder[TraceValue] =
127127
Encoder.instance {
128128
case StringValue(s) => s.asJson
129129
case BooleanValue(b) => b.asJson
@@ -138,6 +138,7 @@ private[logodin] object LogSpan {
138138
case NumberValue(n: BigDecimal) => n.asJson
139139
case NumberValue(n: BigInt) => n.asJson
140140
case NumberValue(n) => n.doubleValue.asJson
141+
case ListValue(vs) => vs.map(EncodeTraceValue(_)).asJson
141142
}
142143

143144
implicit val KeyEncodeCIString: KeyEncoder[CIString] = KeyEncoder[String].contramap(_.toString)

modules/log/shared/src/main/scala/LogSpan.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private[log] final case class LogSpan[F[_]: Sync: Logger: UUIDGen](
111111

112112
private[log] object LogSpan {
113113

114-
implicit val EncodeTraceValue: Encoder[TraceValue] =
114+
implicit lazy val EncodeTraceValue: Encoder[TraceValue] =
115115
Encoder.instance {
116116
case StringValue(s) => s.asJson
117117
case BooleanValue(b) => b.asJson
@@ -126,6 +126,7 @@ private[log] object LogSpan {
126126
case NumberValue(n: BigDecimal) => n.asJson
127127
case NumberValue(n: BigInt) => n.asJson
128128
case NumberValue(n) => n.doubleValue.asJson
129+
case ListValue(vs) => vs.map(EncodeTraceValue(_)).asJson
129130
}
130131

131132
implicit val KeyEncodeCIString: KeyEncoder[CIString] = KeyEncoder[String].contramap(_.toString)

modules/mock/src/main/scala/MockSpan.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import io.opentracing.log.Fields
1313
import io.{opentracing => ot}
1414
import io.opentracing.propagation.{Format, TextMapAdapter}
1515
import io.opentracing.tag.Tags
16-
import natchez.TraceValue.{BooleanValue, NumberValue, StringValue}
16+
import natchez.TraceValue._
1717
import java.net.URI
1818

1919
final case class MockSpan[F[_]: Sync](tracer: ot.mock.MockTracer, span: ot.mock.MockSpan)
@@ -35,6 +35,7 @@ final case class MockSpan[F[_]: Sync](tracer: ot.mock.MockTracer, span: ot.mock.
3535
case (k, StringValue(v)) => Sync[F].delay(span.setTag(k, v))
3636
case (k, NumberValue(v)) => Sync[F].delay(span.setTag(k, v))
3737
case (k, BooleanValue(v)) => Sync[F].delay(span.setTag(k, v))
38+
case (k, ListValue(v)) => Sync[F].delay(span.setTag(k, v.map(_.toString).mkString(", ")))
3839
}
3940

4041
def attachError(err: Throwable, fields: (String, TraceValue)*): F[Unit] =

modules/newrelic/src/main/scala/natchez/newrelic/NewrelicSpan.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import cats.effect.{Resource, Sync}
1111
import cats.syntax.all._
1212
import com.newrelic.telemetry.Attributes
1313
import com.newrelic.telemetry.spans.{Span, SpanBatch, SpanBatchSender}
14-
import natchez.TraceValue.{BooleanValue, NumberValue, StringValue}
14+
import natchez.TraceValue._
1515
import natchez.newrelic.NewrelicSpan.Headers
1616
import natchez.{Kernel, TraceValue}
1717
import org.typelevel.ci._
@@ -48,6 +48,7 @@ private[newrelic] final case class NewrelicSpan[F[_]: Sync](
4848
case (k, StringValue(v)) => attributes.update(att => att.put(k, v))
4949
case (k, NumberValue(v)) => attributes.update(att => att.put(k, v))
5050
case (k, BooleanValue(v)) => attributes.update(att => att.put(k, v))
51+
case (k, ListValue(vs)) => attributes.update(att => att.put(k, vs.mkString(", ")))
5152
}
5253

5354
override def attachError(err: Throwable, fields: (String, TraceValue)*): F[Unit] =

modules/opencensus/src/main/scala/OpenCensusSpan.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import io.opencensus.trace.{AttributeValue, Sampler, SpanBuilder, Tracer, Tracin
1414
import io.opencensus.trace.propagation.SpanContextParseException
1515
import io.opencensus.trace.propagation.TextFormat.Getter
1616
import natchez.Span.{Options, SpanKind}
17-
import natchez.TraceValue.{BooleanValue, NumberValue, StringValue}
17+
import natchez.TraceValue._
1818
import org.typelevel.ci._
1919

2020
import scala.collection.mutable
@@ -40,6 +40,8 @@ private[opencensus] final case class OpenCensusSpan[F[_]: Sync](
4040
AttributeValue.doubleAttributeValue(v.doubleValue())
4141
case BooleanValue(v) =>
4242
AttributeValue.booleanAttributeValue(v)
43+
case ListValue(v) =>
44+
AttributeValue.stringAttributeValue(v.map(_.toString).mkString(", "))
4345
}
4446

4547
override def put(fields: (String, TraceValue)*): F[Unit] =

modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import io.opentelemetry.context.Context
2424

2525
import java.lang
2626
import io.opentelemetry.api.{OpenTelemetry => OTel}
27-
import TraceValue.{BooleanValue, NumberValue, StringValue}
27+
import TraceValue._
2828

2929
import java.net.URI
3030
import scala.collection.mutable
@@ -66,6 +66,16 @@ private[opentelemetry] final case class OpenTelemetrySpan[F[_]: Sync](
6666
// and any other Number can fall back to a Double
6767
case (k, NumberValue(v)) => bldr.put(k, v.doubleValue())
6868
case (k, BooleanValue(v)) => bldr.put(k, v)
69+
case (k, ListValue(vs)) =>
70+
// TODO when support for HLists is merged, stop converting to string
71+
// see https://opentelemetry.io/blog/2025/complex-attribute-types/#upcoming-support-for-complex-attribute-types-in-opentelemetry
72+
val strings: List[String] = vs.collect {
73+
case StringValue(v) => v
74+
case BooleanValue(v) => v.toString
75+
case NumberValue(v) => v.toString
76+
case ListValue(v) => v.mkString(", ")
77+
}
78+
bldr.put(k, strings: _*)
6979
}
7080
bldr.build()
7181
}

0 commit comments

Comments
 (0)