diff --git a/core/common/src/main/scala/org/typelevel/otel4s/AttributeKey.scala b/core/common/src/main/scala/org/typelevel/otel4s/AttributeKey.scala index be06c738c..79d66c05d 100644 --- a/core/common/src/main/scala/org/typelevel/otel4s/AttributeKey.scala +++ b/core/common/src/main/scala/org/typelevel/otel4s/AttributeKey.scala @@ -34,6 +34,11 @@ sealed trait AttributeKey[A] { */ final def apply(value: A): Attribute[A] = Attribute(this, value) + /** @return + * an [[`Attribute`]] associating this key with the given value if the value is defined + */ + final def maybe(value: Option[A]): Option[Attribute[A]] = value.map(apply) + /** @return * an [[`AttributeKey`]] of the same type as this key, with name transformed by `f` */ diff --git a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsBeanstalkDetector.scala b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsBeanstalkDetector.scala index 1b2e226da..930639310 100644 --- a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsBeanstalkDetector.scala +++ b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsBeanstalkDetector.scala @@ -67,9 +67,9 @@ private class AwsBeanstalkDetector[F[_]: Concurrent: Files: Console] private ( builder.addOne(Keys.CloudProvider, Const.CloudProvider) builder.addOne(Keys.CloudPlatform, Const.CloudPlatform) - metadata.deploymentId.foreach(id => builder.addOne(Keys.ServiceInstanceId, id.toString)) - metadata.versionLabel.foreach(v => builder.addOne(Keys.ServiceVersion, v)) - metadata.environmentName.foreach(n => builder.addOne(Keys.ServiceNamespace, n)) + builder.addAll(Keys.ServiceInstanceId.maybe(metadata.deploymentId.map(_.toString))) + builder.addAll(Keys.ServiceVersion.maybe(metadata.versionLabel)) + builder.addAll(Keys.ServiceNamespace.maybe(metadata.environmentName)) TelemetryResource(builder.result(), Some(SchemaUrls.Current)) } diff --git a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsEcsDetector.scala b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsEcsDetector.scala index 5c18f1cd0..eaed87f9e 100644 --- a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsEcsDetector.scala +++ b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsEcsDetector.scala @@ -86,14 +86,14 @@ private class AwsEcsDetector[F[_]: Async: Network: Env: Console] private ( builder.addOne(Keys.CloudPlatform, Const.CloudPlatform) builder.addOne(Keys.CloudResourceId, container.containerArn) builder.addOne(Keys.CloudAvailabilityZones, task.availabilityZone) - regionOpt.foreach(region => builder.addOne(Keys.CloudRegion, region)) - accountIdOpt.foreach(accountId => builder.addOne(Keys.CloudAccountId, accountId)) + builder.addAll(Keys.CloudRegion.maybe(regionOpt)) + builder.addAll(Keys.CloudAccountId.maybe(accountIdOpt)) // container builder.addOne(Keys.ContainerId, container.dockerId) builder.addOne(Keys.ContainerName, container.dockerName) - imageNameOpt.foreach(name => builder.addOne(Keys.ContainerImageName, name)) - imageTagOpt.foreach(tag => builder.addOne(Keys.ContainerImageTags, Seq(tag))) + builder.addAll(Keys.ContainerImageName.maybe(imageNameOpt)) + builder.addAll(Keys.ContainerImageTags.maybe(imageTagOpt.map(Seq(_)))) // aws builder.addOne(Keys.AwsLogGroupNames, Seq(container.logOptions.group)) diff --git a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsLambdaDetector.scala b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsLambdaDetector.scala index e6b7f4f5a..9e39f6426 100644 --- a/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsLambdaDetector.scala +++ b/sdk-contrib/aws/resource/src/main/scala/org/typelevel/otel4s/sdk/contrib/aws/resource/AwsLambdaDetector.scala @@ -51,9 +51,9 @@ private class AwsLambdaDetector[F[_]: Env: Monad] extends TelemetryResourceDetec builder.addOne(Keys.CloudProvider, Const.CloudProvider) builder.addOne(Keys.CloudPlatform, Const.CloudPlatform) - region.foreach(r => builder.addOne(Keys.CloudRegion, r)) - functionName.foreach(name => builder.addOne(Keys.FaasName, name)) - functionVersion.foreach(v => builder.addOne(Keys.FaasVersion, v)) + builder.addAll(Keys.CloudRegion.maybe(region)) + builder.addAll(Keys.FaasName.maybe(functionName)) + builder.addAll(Keys.FaasVersion.maybe(functionVersion)) TelemetryResource(builder.result(), Some(SchemaUrls.Current)) } diff --git a/sdk/common/jvm-native/src/main/scala/org/typelevel/otel4s/sdk/resource/OSDetectorPlatform.scala b/sdk/common/jvm-native/src/main/scala/org/typelevel/otel4s/sdk/resource/OSDetectorPlatform.scala index 418ebc575..bc6df6b7f 100644 --- a/sdk/common/jvm-native/src/main/scala/org/typelevel/otel4s/sdk/resource/OSDetectorPlatform.scala +++ b/sdk/common/jvm-native/src/main/scala/org/typelevel/otel4s/sdk/resource/OSDetectorPlatform.scala @@ -38,16 +38,24 @@ private[resource] trait OSDetectorPlatform { self: OSDetector.type => nameOpt <- Sync[F].delay(sys.props.get("os.name")) versionOpt <- Sync[F].delay(sys.props.get("os.version")) } yield { - val tpe = nameOpt.flatMap(nameToType).map(Keys.Type(_)) + val builder = Attributes.newBuilder - val description = versionOpt - .zip(nameOpt) - .map { case (version, name) => - Keys.Description(name + " " + version) - } - .orElse(nameOpt.map(Keys.Description(_))) + val tpe = Keys.Type.maybe(nameOpt.flatMap(nameToType)) + + val description = { + val value = versionOpt + .zip(nameOpt) + .map { case (version, name) => name + " " + version } + .orElse(nameOpt) + + Keys.Description.maybe(value) + } + + builder.addAll(tpe) + builder.addAll(description) + + val attributes = builder.result() - val attributes = tpe.to(Attributes) ++ description.to(Attributes) Option.when(attributes.nonEmpty)( TelemetryResource(attributes, Some(SchemaUrls.Current)) ) diff --git a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala index c40859fe7..afa05b656 100644 --- a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala +++ b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala @@ -36,15 +36,16 @@ private[resource] trait HostDetectorPlatform { self: HostDetector.type => def detect: F[Option[TelemetryResource]] = for { - hostOpt <- Sync[F] - .blocking(InetAddress.getLocalHost.getHostName) - .redeem(_ => None, Some(_)) - - archOpt <- Sync[F].delay(sys.props.get("os.arch")) + host <- Sync[F].blocking(InetAddress.getLocalHost.getHostName).redeem(_ => None, Some(_)) + arch <- Sync[F].delay(sys.props.get("os.arch")) } yield { - val host = hostOpt.map(Keys.Host(_)) - val arch = archOpt.map(Keys.Arch(_)) - val attributes = host.to(Attributes) ++ arch.to(Attributes) + val builder = Attributes.newBuilder + + builder.addAll(Keys.Host.maybe(host)) + builder.addAll(Keys.Arch.maybe(arch)) + + val attributes = builder.result() + Option.when(attributes.nonEmpty)( TelemetryResource(attributes, Some(SchemaUrls.Current)) ) diff --git a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessDetectorPlatform.scala b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessDetectorPlatform.scala index d8fdba78e..b86901d31 100644 --- a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessDetectorPlatform.scala +++ b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessDetectorPlatform.scala @@ -49,7 +49,7 @@ private[resource] trait ProcessDetectorPlatform { self: ProcessDetector.type => } yield { val builder = Attributes.newBuilder - getPid(runtime).foreach(pid => builder.addOne(Keys.Pid(pid))) + builder.addAll(Keys.Pid.maybe(getPid(runtime))) javaHomeOpt.foreach { javaHome => val exePath = executablePath(javaHome, osNameOpt) diff --git a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessRuntimeDetectorPlatform.scala b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessRuntimeDetectorPlatform.scala index 384feeaba..cac6e99df 100644 --- a/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessRuntimeDetectorPlatform.scala +++ b/sdk/common/jvm/src/main/scala/org/typelevel/otel4s/sdk/resource/ProcessRuntimeDetectorPlatform.scala @@ -43,11 +43,14 @@ private[resource] trait ProcessRuntimeDetectorPlatform { } yield { val attributes = Attributes.newBuilder - runtimeName.foreach(name => attributes.addOne(Keys.Name(name))) - runtimeVersion.foreach(name => attributes.addOne(Keys.Version(name))) - (vmVendor, vmName, vmVersion).mapN { (vendor, name, version) => - attributes.addOne(Keys.Description(s"$vendor $name $version")) - } + val description = + (vmVendor, vmName, vmVersion).mapN { (vendor, name, version) => + s"$vendor $name $version" + } + + attributes.addAll(Keys.Name.maybe(runtimeName)) + attributes.addAll(Keys.Version.maybe(runtimeVersion)) + attributes.addAll(Keys.Description.maybe(description)) Some(TelemetryResource(attributes.result(), Some(SchemaUrls.Current))) } diff --git a/sdk/common/native/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala b/sdk/common/native/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala index 3b33c1c61..19326c1f2 100644 --- a/sdk/common/native/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala +++ b/sdk/common/native/src/main/scala/org/typelevel/otel4s/sdk/resource/HostDetectorPlatform.scala @@ -38,12 +38,16 @@ private[resource] trait HostDetectorPlatform { self: HostDetector.type => def detect: F[Option[TelemetryResource]] = for { - hostOpt <- Sync[F].delay(detectHost).handleError(_ => None) - archOpt <- Sync[F].delay(sys.props.get("os.arch")) + host <- Sync[F].delay(detectHost).handleError(_ => None) + arch <- Sync[F].delay(sys.props.get("os.arch")) } yield { - val host = hostOpt.map(Keys.Host(_)) - val arch = archOpt.map(Keys.Arch(_)) - val attributes = host.to(Attributes) ++ arch.to(Attributes) + val builder = Attributes.newBuilder + + builder.addAll(Keys.Host.maybe(host)) + builder.addAll(Keys.Arch.maybe(arch)) + + val attributes = builder.result() + Option.when(attributes.nonEmpty)( TelemetryResource(attributes, Some(SchemaUrls.Current)) )