Skip to content

Commit

Permalink
Add AttributeConverters
Browse files Browse the repository at this point in the history
Add `AttributeConverters` for converting between Java and Scala
`AttributeKey`s and `Attributes`.
  • Loading branch information
NthPortal committed Mar 12, 2024
1 parent 6f47c84 commit d9b8924
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import io.opentelemetry.sdk.trace.data.StatusData
import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.context.propagation.TextMapPropagator
import org.typelevel.otel4s.oteljava.AttributeConverters._
import org.typelevel.otel4s.oteljava.context.Context
import org.typelevel.otel4s.oteljava.context.propagation.PropagatorConverters._
import org.typelevel.otel4s.oteljava.testkit.Conversions
import org.typelevel.otel4s.oteljava.testkit.trace.TracesTestkit
import org.typelevel.otel4s.trace.BaseTracerSuite
import org.typelevel.otel4s.trace.SpanContext
Expand Down Expand Up @@ -155,7 +155,7 @@ class TracerSuite extends BaseTracerSuite[Context, Context.Key] {
)

def attributes: Attributes =
Conversions.fromJAttributes(sd.getAttributes)
sd.getAttributes.toScala

def startTimestamp: FiniteDuration =
sd.getStartEpochNanos.nanos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,11 @@

package org.typelevel.otel4s.oteljava.testkit

import _root_.java.{lang => jl}
import _root_.java.{util => ju}
import cats.effect.Async
import cats.syntax.either._
import io.opentelemetry.api.common.{AttributeType => JAttributeType}
import io.opentelemetry.api.common.{Attributes => JAttributes}
import io.opentelemetry.sdk.common.CompletableResultCode
import org.typelevel.otel4s.Attribute
import org.typelevel.otel4s.Attributes

import scala.jdk.CollectionConverters._

private[oteljava] object Conversions {

def fromJAttributes(attributes: JAttributes): Attributes = {
val converted = attributes.asMap().asScala.toList.collect {
case (attribute, value: String)
if attribute.getType == JAttributeType.STRING =>
Attribute(attribute.getKey, value)

case (attribute, value: jl.Boolean)
if attribute.getType == JAttributeType.BOOLEAN =>
Attribute(attribute.getKey, value.booleanValue())

case (attribute, value: jl.Long)
if attribute.getType == JAttributeType.LONG =>
Attribute(attribute.getKey, value.longValue())

case (attribute, value: jl.Double)
if attribute.getType == JAttributeType.DOUBLE =>
Attribute(attribute.getKey, value.doubleValue())

case (attribute, value: ju.List[String] @unchecked)
if attribute.getType == JAttributeType.STRING_ARRAY =>
Attribute(attribute.getKey, value.asScala.toList)

case (attribute, value: ju.List[jl.Boolean] @unchecked)
if attribute.getType == JAttributeType.BOOLEAN_ARRAY =>
Attribute(attribute.getKey, value.asScala.toList.map(_.booleanValue()))

case (attribute, value: ju.List[jl.Long] @unchecked)
if attribute.getType == JAttributeType.LONG_ARRAY =>
Attribute(attribute.getKey, value.asScala.toList.map(_.longValue()))

case (attribute, value: ju.List[jl.Double] @unchecked)
if attribute.getType == JAttributeType.DOUBLE_ARRAY =>
Attribute(attribute.getKey, value.asScala.toList.map(_.doubleValue()))
}

converted.to(Attributes)
}

def asyncFromCompletableResultCode[F[_]](
codeF: F[CompletableResultCode],
msg: => Option[String] = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.opentelemetry.sdk.common.{
InstrumentationScopeInfo => JInstrumentationScopeInfo
}
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.oteljava.AttributeConverters._

/** A representation of the
* `io.opentelemetry.sdk.common.InstrumentationScopeInfo`.
Expand Down Expand Up @@ -67,7 +68,7 @@ object InstrumentationScope {
name = scope.getName,
version = Option(scope.getVersion),
schemaUrl = Option(scope.getSchemaUrl),
attributes = Conversions.fromJAttributes(scope.getAttributes)
attributes = scope.getAttributes.toScala
)

implicit val instrumentationScopeHash: Hash[InstrumentationScope] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import cats.Show
import cats.syntax.show._
import io.opentelemetry.sdk.resources.{Resource => JResource}
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.oteljava.AttributeConverters._

/** A representation of the `io.opentelemetry.sdk.resources.Resource`.
*/
Expand Down Expand Up @@ -57,7 +58,7 @@ object TelemetryResource {
def apply(resource: JResource): TelemetryResource =
Impl(
schemaUrl = Option(resource.getSchemaUrl),
attributes = Conversions.fromJAttributes(resource.getAttributes)
attributes = resource.getAttributes.toScala
)

implicit val telemetryResourceHash: Hash[TelemetryResource] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* Copyright 2022 Typelevel
*
* 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.
*/

/*
* The scaladocs in this file are adapted from those in the file
* scala/jdk/CollectionConverters.scala
* in the Scala standard library.
*/

package org.typelevel.otel4s.oteljava

import io.opentelemetry.api.common.{AttributeKey => JAttributeKey}
import io.opentelemetry.api.common.{AttributeType => JAttributeType}
import io.opentelemetry.api.common.{Attributes => JAttributes}
import org.typelevel.otel4s.Attribute
import org.typelevel.otel4s.AttributeKey
import org.typelevel.otel4s.AttributeType
import org.typelevel.otel4s.Attributes

import java.{util => ju}
import scala.collection.immutable
import scala.jdk.CollectionConverters._

/** This object provides extension methods that convert between Scala and Java
* `AttributeKey`s and `Attributes` using `toScala` and `toJava` extension
* methods, as well as a `toJavaAttributes` extension method that converts
* `immutable.Iterable[Attribute[_]]` to Java `Attributes`.
*
* {{{
* import io.opentelemetry.api.common.{Attributes => JAttributes}
* import org.typelevel.otel4s.Attributes
* import org.typelevel.otel4s.oteljava.AttributeConverters._
*
* val attributes: Attributes =
* io.opentelemetry.api.common.Attributes.builder()
* .put("key", "value")
* .build()
* .toScala
* }}}
*
* The conversions do not return wrappers.
*/
object AttributeConverters {

implicit final class AttributeKeyHasToJava(private val key: AttributeKey[_])
extends AnyVal {

/** Converts a Scala `AttributeKey` to a Java `AttributeKey`. */
def toJava: JAttributeKey[_] = Explicit.toJava(key)
}

implicit final class AttributesHasToJava(private val attributes: Attributes)
extends AnyVal {

/** Converts Scala `Attributes` to Java `Attributes`. */
def toJava: JAttributes = Explicit.toJava(attributes)
}

implicit final class IterableAttributeHasToJava(
private val attributes: immutable.Iterable[Attribute[_]]
) extends AnyVal {

/** Converts an immutable collection of Scala `Attribute`s to Java
* `Attributes`.
*/
def toJavaAttributes: JAttributes = Explicit.toJavaAttributes(attributes)
}

implicit final class AttributeKeyHasToScala(private val key: JAttributeKey[_])
extends AnyVal {

/** Converts a Java `AttributeKey` to a Scala `AttributeKey`. */
def toScala: AttributeKey[_] = Explicit.toScala(key)
}

implicit final class AttributesHasToScala(private val attributes: JAttributes)
extends AnyVal {

/** Converts Scala `Attributes` to Java `Attributes`. */
def toScala: Attributes = Explicit.toScala(attributes)
}

private object Explicit {
def toJava(key: AttributeKey[_]): JAttributeKey[_] =
key.`type` match {
case AttributeType.String => JAttributeKey.stringKey(key.name)
case AttributeType.Boolean => JAttributeKey.booleanKey(key.name)
case AttributeType.Long => JAttributeKey.longKey(key.name)
case AttributeType.Double => JAttributeKey.doubleKey(key.name)
case AttributeType.StringList => JAttributeKey.stringArrayKey(key.name)
case AttributeType.BooleanList =>
JAttributeKey.booleanArrayKey(key.name)
case AttributeType.LongList => JAttributeKey.longArrayKey(key.name)
case AttributeType.DoubleList => JAttributeKey.doubleArrayKey(key.name)
}

final def toJava(attributes: Attributes): JAttributes =
toJavaAttributes(attributes)

def toJavaAttributes(
attributes: immutable.Iterable[Attribute[_]]
): JAttributes = {
val builder = JAttributes.builder

attributes.foreach { case Attribute(key, value) =>
key.`type` match {
case AttributeType.String =>
builder.put(key.name, value.asInstanceOf[String])
case AttributeType.Boolean =>
builder.put(key.name, value.asInstanceOf[Boolean])
case AttributeType.Long =>
builder.put(key.name, value.asInstanceOf[Long])
case AttributeType.Double =>
builder.put(key.name, value.asInstanceOf[Double])
case AttributeType.StringList =>
builder.put(key.name, value.asInstanceOf[List[String]]: _*)
case AttributeType.BooleanList =>
builder.put(key.name, value.asInstanceOf[List[Boolean]]: _*)
case AttributeType.LongList =>
builder.put(key.name, value.asInstanceOf[List[Long]]: _*)
case AttributeType.DoubleList =>
builder.put(key.name, value.asInstanceOf[List[Double]]: _*)
}
}

builder.build()
}

def toScala(key: JAttributeKey[_]): AttributeKey[_] =
key.getType match {
case JAttributeType.STRING => AttributeKey.string(key.getKey)
case JAttributeType.BOOLEAN => AttributeKey.boolean(key.getKey)
case JAttributeType.LONG => AttributeKey.long(key.getKey)
case JAttributeType.DOUBLE => AttributeKey.double(key.getKey)
case JAttributeType.STRING_ARRAY => AttributeKey.stringList(key.getKey)
case JAttributeType.BOOLEAN_ARRAY =>
AttributeKey.booleanList(key.getKey)
case JAttributeType.LONG_ARRAY => AttributeKey.longList(key.getKey)
case JAttributeType.DOUBLE_ARRAY => AttributeKey.doubleList(key.getKey)
}

def toScala(attributes: JAttributes): Attributes = {
val builder = Attributes.newBuilder

attributes.forEach { (key: JAttributeKey[_], value: Any) =>
key.getType match {
case JAttributeType.STRING =>
builder.addOne(key.getKey, value.asInstanceOf[String])
case JAttributeType.BOOLEAN =>
builder.addOne(key.getKey, value.asInstanceOf[Boolean])
case JAttributeType.LONG =>
builder.addOne(key.getKey, value.asInstanceOf[Long])
case JAttributeType.DOUBLE =>
builder.addOne(key.getKey, value.asInstanceOf[Double])
case JAttributeType.STRING_ARRAY =>
builder.addOne(
key.getKey,
value.asInstanceOf[ju.List[String]].asScala.toList
)
case JAttributeType.BOOLEAN_ARRAY =>
builder.addOne(
key.getKey,
value.asInstanceOf[ju.List[Boolean]].asScala.toList
)
case JAttributeType.LONG_ARRAY =>
builder.addOne(
key.getKey,
value.asInstanceOf[ju.List[Long]].asScala.toList
)
case JAttributeType.DOUBLE_ARRAY =>
builder.addOne(
key.getKey,
value.asInstanceOf[ju.List[Double]].asScala.toList
)
}
}

builder.result()
}
}
}

This file was deleted.

Loading

0 comments on commit d9b8924

Please sign in to comment.