Skip to content

Commit

Permalink
Merge pull request #724 from iRevive/sdk-common/runtime-detector
Browse files Browse the repository at this point in the history
sdk-common: add `ProcessRuntimeDetector`
  • Loading branch information
iRevive authored Aug 21, 2024
2 parents bbd4307 + ebb319a commit 2604ca7
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/sdk/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ If not specified, SDK defaults the service name to `unknown_service:scala`.
| otel.resource.attributes | OTEL\\_RESOURCE\\_ATTRIBUTES | Specify resource attributes in the following format: `key1=val1,key2=val2,key3=val3`. |
| otel.service.name | OTEL\\_SERVICE\\_NAME | Specify logical service name. Takes precedence over `service.name` defined with `otel.resource.attributes`. |
| otel.experimental.resource.disabled-keys | OTEL\\_EXPERIMENTAL\\_RESOURCE\\_DISABLED\\_KEYS | Specify resource attribute keys that are filtered. |
| otel.otel4s.resource.detectors | OTEL\\_OTEL4S\\_RESOURCE\\_DETECTORS | Specify resource detectors to use. Defaults to `host,os`. |
| otel.otel4s.resource.detectors | OTEL\\_OTEL4S\\_RESOURCE\\_DETECTORS | Specify resource detectors to use. Defaults to `host,os,process_runtime`. |

## Metrics

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ object OpenTelemetrySdk {
* By default, the following detectors are enabled:
* - host: `host.arch`, `host.name`
* - os: `os.type`, `os.description`
* - process_runtime: `process.runtime.name`,
* `process.runtime.version`, `process.runtime.description`
*
* @param detector
* the detector to add
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ package org.typelevel.otel4s.sdk.resource
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

/** A mapping of the Node.js OS API.
*
* @see
* [[https://nodejs.org/api/os.html]]
*/
private object OS {

@js.native
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2023 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.
*/

package org.typelevel.otel4s.sdk.resource

import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

/** A mapping of the Node.js process API.
*
* @see
* [[https://nodejs.org/api/process.html]]
*/
private object Process {

@js.native
@JSImport("process", "versions")
def versions: Versions = js.native

@js.native
trait Versions extends js.Object {
def node: String = js.native
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2023 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.
*/

package org.typelevel.otel4s.sdk.resource

import cats.effect.Sync
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.sdk.TelemetryResource
import org.typelevel.otel4s.semconv.SchemaUrls

private[resource] trait ProcessRuntimeDetectorPlatform {
self: ProcessRuntimeDetector.type =>

def apply[F[_]: Sync]: TelemetryResourceDetector[F] =
new Detector[F]

private class Detector[F[_]: Sync] extends TelemetryResourceDetector[F] {
def name: String = Const.Name

def detect: F[Option[TelemetryResource]] = Sync[F].delay {
val attributes = Attributes(
Keys.Name("nodejs"),
Keys.Version(Process.versions.node),
Keys.Description("Node.js")
)

Some(TelemetryResource(attributes, Some(SchemaUrls.Current)))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 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.
*/

package org.typelevel.otel4s.sdk.resource

import cats.effect.Sync
import cats.syntax.apply._
import cats.syntax.flatMap._
import cats.syntax.functor._
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.sdk.TelemetryResource
import org.typelevel.otel4s.semconv.SchemaUrls

private[resource] trait ProcessRuntimeDetectorPlatform {
self: ProcessRuntimeDetector.type =>

def apply[F[_]: Sync]: TelemetryResourceDetector[F] =
new Detector[F]

private class Detector[F[_]: Sync] extends TelemetryResourceDetector[F] {
def name: String = Const.Name

def detect: F[Option[TelemetryResource]] =
for {
runtimeName <- Sync[F].delay(sys.props.get("java.runtime.name"))
runtimeVersion <- Sync[F].delay(sys.props.get("java.runtime.version"))
vmVendor <- Sync[F].delay(sys.props.get("java.vm.vendor"))
vmName <- Sync[F].delay(sys.props.get("java.vm.name"))
vmVersion <- Sync[F].delay(sys.props.get("java.vm.version"))
} 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"))
}

Some(TelemetryResource(attributes.result(), Some(SchemaUrls.Current)))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2023 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.
*/

package org.typelevel.otel4s.sdk.resource

import cats.effect.Sync
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.sdk.TelemetryResource
import org.typelevel.otel4s.semconv.SchemaUrls

private[resource] trait ProcessRuntimeDetectorPlatform {
self: ProcessRuntimeDetector.type =>

def apply[F[_]: Sync]: TelemetryResourceDetector[F] =
new Detector[F]

private class Detector[F[_]: Sync] extends TelemetryResourceDetector[F] {
def name: String = Const.Name

def detect: F[Option[TelemetryResource]] =
Sync[F].delay {
val attributes = Attributes(
Keys.Name("scalanative"),
// Keys.Version(""), not available yet
Keys.Description("Scala Native")
)

Some(TelemetryResource(attributes, Some(SchemaUrls.Current)))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import java.nio.charset.StandardCharsets
* | otel.resource.attributes | OTEL_RESOURCE_ATTRIBUTES | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
* | otel.service.name | OTEL_SERVICE_NAME | Specify logical service name. Takes precedence over `service.name` defined with `otel.resource.attributes` |
* | otel.experimental.resource.disabled-keys | OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS | Specify resource attribute keys that are filtered. |
* | otel.otel4s.resource.detectors | OTEL_OTEL4S_RESOURCE_DETECTORS | Specify resource detectors to use. Defaults to `host,os`. |
* | otel.otel4s.resource.detectors | OTEL_OTEL4S_RESOURCE_DETECTORS | Specify resource detectors to use. Defaults to `host,os,process_runtime`. |
* }}}
*
* @see
Expand Down Expand Up @@ -205,7 +205,8 @@ private[sdk] object TelemetryResourceAutoConfigure {
private object Defaults {
val Detectors: Set[String] = Set(
HostDetector.Const.Name,
OSDetector.Const.Name
OSDetector.Const.Name,
ProcessRuntimeDetector.Const.Name
)
}

Expand All @@ -218,7 +219,7 @@ private[sdk] object TelemetryResourceAutoConfigure {
* | otel.resource.attributes | OTEL_RESOURCE_ATTRIBUTES | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
* | otel.service.name | OTEL_SERVICE_NAME | Specify logical service name. Takes precedence over `service.name` defined with `otel.resource.attributes` |
* | otel.experimental.resource.disabled-keys | OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS | Specify resource attribute keys that are filtered. |
* | otel.otel4s.resource.detectors | OTEL_OTEL4S_RESOURCE_DETECTORS | Specify resource detectors to use. Defaults to `host,os`. |
* | otel.otel4s.resource.detectors | OTEL_OTEL4S_RESOURCE_DETECTORS | Specify resource detectors to use. Defaults to `host,os,process_runtime`. |
* }}}
*
* @see
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2023 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.
*/

package org.typelevel.otel4s.sdk.resource

import org.typelevel.otel4s.AttributeKey

/** Detects runtime details such as name, version, and description.
*
* @see
* https://opentelemetry.io/docs/specs/semconv/resource/process/#process-runtimes
*/
object ProcessRuntimeDetector extends ProcessRuntimeDetectorPlatform {

private[sdk] object Const {
val Name = "process_runtime"
}

private[resource] object Keys {
val Name: AttributeKey[String] =
AttributeKey("process.runtime.name")

val Version: AttributeKey[String] =
AttributeKey("process.runtime.version")

val Description: AttributeKey[String] =
AttributeKey("process.runtime.description")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ object TelemetryResourceDetector {
* Includes:
* - host detector
* - os detector
* - process runtime detector
*
* @tparam F
* the higher-kinded type of a polymorphic effect
*/
def default[F[_]: Sync]: Set[TelemetryResourceDetector[F]] =
Set(HostDetector[F], OSDetector[F])
Set(HostDetector[F], OSDetector[F], ProcessRuntimeDetector[F])

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package autoconfigure

import cats.effect.IO
import munit.CatsEffectSuite
import munit.internal.PlatformCompat
import org.typelevel.otel4s.sdk.resource.TelemetryResourceDetector

class TelemetryResourceAutoConfigureSuite extends CatsEffectSuite {
Expand Down Expand Up @@ -70,14 +71,23 @@ class TelemetryResourceAutoConfigureSuite extends CatsEffectSuite {
val host = Set("host.arch", "host.name")
val os = Set("os.type", "os.description")

val runtime = {
val name = "process.runtime.name"
val version = "process.runtime.version"
val description = "process.runtime.description"

if (PlatformCompat.isNative) Set(name, description)
else Set(name, version, description)
}

val telemetry = Set(
"telemetry.sdk.language",
"telemetry.sdk.name",
"telemetry.sdk.version"
)

val all =
host ++ os ++ service ++ telemetry
host ++ os ++ runtime ++ service ++ telemetry

IO(assertEquals(resource.attributes.map(_.key.name).toSet, all))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package org.typelevel.otel4s.sdk.resource

import cats.effect.IO
import munit.CatsEffectSuite
import munit.internal.PlatformCompat
import org.typelevel.otel4s.semconv.SchemaUrls

class TelemetryResourceDetectorSuite extends CatsEffectSuite {
Expand All @@ -44,9 +45,27 @@ class TelemetryResourceDetectorSuite extends CatsEffectSuite {
}
}

test("default - contain host, os detectors") {
test("ProcessRuntimeDetector - detect name, version, and description") {
val keys = {
val name = "process.runtime.name"
val version = "process.runtime.version"
val description = "process.runtime.description"

if (PlatformCompat.isNative) Set(name, description)
else Set(name, version, description)
}

for {
resource <- ProcessRuntimeDetector[IO].detect
} yield {
assertEquals(resource.map(_.attributes.map(_.key.name).toSet), Some(keys))
assertEquals(resource.flatMap(_.schemaUrl), Some(SchemaUrls.Current))
}
}

test("default - contain host, os, process_runtime detectors") {
val detectors = TelemetryResourceDetector.default[IO].map(_.name)
val expected = Set("host", "os")
val expected = Set("host", "os", "process_runtime")

assertEquals(detectors.map(_.name), expected)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ object SdkMetrics {
* By default, the following detectors are enabled:
* - host: `host.arch`, `host.name`
* - os: `os.type`, `os.description`
* - process_runtime: `process.runtime.name`,
* `process.runtime.version`, `process.runtime.description`
*
* @param detector
* the detector to add
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ object SdkTraces {
* By default, the following detectors are enabled:
* - host: `host.arch`, `host.name`
* - os: `os.type`, `os.description`
* - process_runtime: `process.runtime.name`,
* `process.runtime.version`, `process.runtime.description`
*
* @param detector
* the detector to add
Expand Down

0 comments on commit 2604ca7

Please sign in to comment.