Skip to content

Commit 99751a5

Browse files
authored
Merge pull request #1157 from hughsimpson/OTEL_RESOURCE_ATTRIBUTES-support
Otel resource attributes support
2 parents 140c697 + db3312a commit 99751a5

File tree

4 files changed

+20
-3
lines changed

4 files changed

+20
-3
lines changed

reporters/kamon-opentelemetry/src/main/resources/reference.conf

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ kamon.otel {
2323
protocol = "grpc"
2424
protocol = ${?OTEL_EXPORTER_OTLP_PROTOCOL}
2525

26+
# Support for OTEL_RESOURCE_ATTRIBUTES env var (cf https://opentelemetry.io/docs/reference/specification/resource/sdk/)
27+
attributes = ""
28+
attributes = ${?OTEL_RESOURCE_ATTRIBUTES}
29+
2630
trace {
2731
endpoint = ${kamon.otel.endpoint}
2832
full-endpoint = ${?OTEL_EXPORTER_OTLP_TRACES_ENDPOINT}

reporters/kamon-opentelemetry/src/main/scala/kamon/otel/OpenTelemetryTraceReporter.scala

+12-3
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import kamon.Kamon
2222
import kamon.module.{Module, ModuleFactory, SpanReporter}
2323
import kamon.trace.Span
2424
import org.slf4j.LoggerFactory
25+
import java.net.URLDecoder
2526
import java.util.{Collection => JCollection}
2627

2728
import scala.concurrent.ExecutionContext
28-
import scala.util.{Failure, Success}
29+
import scala.util.{Failure, Success, Try}
2930

3031
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo
3132
import io.opentelemetry.sdk.resources.Resource
@@ -73,7 +74,14 @@ class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(im
7374
logger.info("Reconfigure OpenTelemetry Trace Reporter")
7475

7576
//pre-generate the function for converting Kamon span to proto span
76-
val resource: Resource = buildResource
77+
val attributes: Map[String, String] =
78+
newConfig.getString("kamon.otel.attributes").split(',').filter(_ contains '=').map(_.trim.split("=", 2)).map {
79+
case Array(k, v) =>
80+
val decoded = Try(URLDecoder.decode(v.trim, "UTF-8"))
81+
decoded.failed.foreach(t => throw new IllegalArgumentException(s"value for attribute ${k.trim} is not a url-encoded string", t))
82+
k.trim -> decoded.get
83+
}.toMap
84+
val resource: Resource = buildResource(attributes)
7785
this.spanConverterFunc = SpanConverter.convert(newConfig.getBoolean("kamon.otel.trace.include-error-event"), resource, kamonSettings.version)
7886

7987
this.traceService = Option(traceServiceFactory.apply(newConfig))
@@ -90,7 +98,7 @@ class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(im
9098
*
9199
* @return
92100
*/
93-
private def buildResource: Resource = {
101+
private def buildResource(attributes: Map[String, String]): Resource = {
94102
val env = Kamon.environment
95103
val builder = Resource.builder()
96104
.put("host.name", kamonSettings.environment.host)
@@ -100,6 +108,7 @@ class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(im
100108
.put("telemetry.sdk.language", "scala")
101109
.put("telemetry.sdk.version", kamonSettings.version)
102110

111+
attributes.foreach { case (k, v) => builder.put(k, v) }
103112
//add all kamon.environment.tags as KeyValues to the Resource object
104113
env.tags.iterator().foreach {
105114
case t: Tag.String => builder.put(t.key, t.value)

reporters/kamon-opentelemetry/src/test/resources/application.conf

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ kamon {
1212
env = "kamon-devint"
1313
}
1414
}
15+
otel.attributes = "att1=v1, att2 = v2 ,att3=+a%3Db%2Cc%3Dd+"
1516
}

reporters/kamon-opentelemetry/src/test/scala/kamon/otel/OpenTelemetryTraceReporterSpec.scala

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class OpenTelemetryTraceReporterSpec extends AnyWordSpec with Matchers with Opti
6262
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.version"), kamonVersion)
6363
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("service.version"), "x.x.x")
6464
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("env"), "kamon-devint")
65+
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att1"), "v1")
66+
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att2"), "v2")
67+
spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att3"), " a=b,c=d ")
6568
val host = spanData.getResource.getAttributes.asMap().asScala.get(AttributeKey.stringKey("host.name"))
6669
host shouldBe defined
6770
val instance = spanData.getResource.getAttributes.asMap().asScala.get(AttributeKey.stringKey("service.instance.id"))

0 commit comments

Comments
 (0)