Skip to content

Commit

Permalink
sdk-contrib: add aws-resource module
Browse files Browse the repository at this point in the history
  • Loading branch information
iRevive committed Sep 9, 2024
1 parent 65b9c1e commit a383be7
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 4 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target sdk-exporter/common/.native/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-exporter/metrics/.native/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk-exporter/trace/.native/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray-propagator/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target project/target
run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target sdk-exporter/common/.native/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-exporter/metrics/.native/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk-exporter/trace/.native/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk-contrib/aws/resource/.native/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray-propagator/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target sdk-exporter/common/.native/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-exporter/metrics/.native/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk-exporter/trace/.native/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray-propagator/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target project/target
run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target sdk-exporter/common/.native/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-exporter/metrics/.native/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk-exporter/trace/.native/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk-contrib/aws/resource/.native/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray-propagator/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
22 changes: 20 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ lazy val root = tlCrossRootProject
`sdk-exporter-metrics`,
`sdk-exporter-trace`,
`sdk-exporter`,
`sdk-contrib-aws-resource`,
`sdk-contrib-aws-xray-propagator`,
`oteljava-common`,
`oteljava-common-testkit`,
Expand Down Expand Up @@ -437,6 +438,22 @@ lazy val `sdk-exporter` = crossProject(JVMPlatform, JSPlatform, NativePlatform)
// SDK contrib modules
//

lazy val `sdk-contrib-aws-resource` =
crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
.in(file("sdk-contrib/aws/resource"))
.dependsOn(`sdk-common`, `semconv-experimental` % Test)
.settings(
name := "otel4s-sdk-contrib-aws-resource",
startYear := Some(2024)
)
.settings(munitDependencies)
.settings(scalafixSettings)

//
// SDK contrib modules
//

lazy val `sdk-contrib-aws-xray-propagator` =
crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
Expand All @@ -447,8 +464,7 @@ lazy val `sdk-contrib-aws-xray-propagator` =
)
.settings(
name := "otel4s-sdk-contrib-aws-xray-propagator",
startYear := Some(2024),
mimaPreviousArtifacts ~= { _.filterNot(_.revision.startsWith("0.9")) }
startYear := Some(2024)
)
.settings(munitDependencies)
.settings(scalafixSettings)
Expand Down Expand Up @@ -680,6 +696,7 @@ lazy val docs = project
oteljava,
sdk.jvm,
`sdk-exporter`.jvm,
`sdk-contrib-aws-resource`.jvm,
`sdk-contrib-aws-xray-propagator`.jvm
)
.settings(
Expand Down Expand Up @@ -753,6 +770,7 @@ lazy val unidocs = project
`sdk-exporter-metrics`.jvm,
`sdk-exporter-trace`.jvm,
`sdk-exporter`.jvm,
`sdk-contrib-aws-resource`.jvm,
`sdk-contrib-aws-xray-propagator`.jvm,
`oteljava-common`,
`oteljava-common-testkit`,
Expand Down
186 changes: 186 additions & 0 deletions docs/sdk/aws-resource-detectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# AWS | Resource detectors

Resource detectors can add environment-specific attributes to the telemetry resource.
AWS detectors are implemented as a third-party library, and you need to enable them manually.

## The list of detectors

### 1. aws-lambda

The detector relies on the `AWS_REGION`, `AWS_LAMBDA_FUNCTION_NAME`, and `AWS_LAMBDA_FUNCTION_VERSION` environment variables
to configure the telemetry resource.
Either `AWS_LAMBDA_FUNCTION_NAME` or `AWS_LAMBDA_FUNCTION_VERSION` must be present.

```scala mdoc:passthrough
import cats.effect.IO
import cats.effect.std.Env
import cats.effect.unsafe.implicits.global
import org.typelevel.otel4s.sdk.contrib.aws.resource._
import scala.collection.immutable

val envEntries = Map(
"AWS_REGION" -> "eu-west-1",
"AWS_LAMBDA_FUNCTION_NAME" -> "function",
"AWS_LAMBDA_FUNCTION_VERSION" -> "0.0.1"
)

implicit val env: Env[IO] =
new Env[IO] {
def get(name: String): IO[Option[String]] = IO.pure(envEntries.get(name))
def entries: IO[immutable.Iterable[(String, String)]] = IO.pure(envEntries)
}

println("Environment: ")
println("```")
envEntries.foreach { case (k, v) => println(s"${k.replace("_", "_")}=$v") }
println("```")

println("Detected resource: ")
println("```")
AWSLambdaDetector[IO].detect.unsafeRunSync().foreach { resource =>
resource.attributes.toList.sortBy(_.key.name).foreach { attribute =>
println(attribute.key.name + ": " + attribute.value)
}
}
println("```")
```

## Getting Started

@:select(build-tool)

@:choice(sbt)

Add settings to the `build.sbt`:

```scala
libraryDependencies ++= Seq(
"org.typelevel" %%% "otel4s-sdk" % "@VERSION@", // <1>
"org.typelevel" %%% "otel4s-sdk-exporter" % "@VERSION@", // <2>
"org.typelevel" %%% "otel4s-sdk-contrib-aws-resource" % "@VERSION@" // <3>
)
```

@:choice(scala-cli)

Add directives to the `*.scala` file:

```scala
//> using lib "org.typelevel::otel4s-sdk::@VERSION@" // <1>
//> using lib "org.typelevel::otel4s-sdk-exporter::@VERSION@" // <2>
//> using lib "org.typelevel::otel4s-sdk-contrib-aws-resource::@VERSION@" // <3>
```

@:@

1. Add the `otel4s-sdk` library
2. Add the `otel4s-sdk-exporter` library. Without the exporter, the application will crash
3. Add the `otel4s-sdk-contrib-aws-resource` library

_______

Then autoconfigure the SDK:

@:select(sdk-entry-point)

@:choice(sdk)

`OpenTelemetrySdk.autoConfigured` configures both `MeterProvider` and `TracerProvider`:

```scala mdoc:silent:reset
import cats.effect.{IO, IOApp}
import org.typelevel.otel4s.metrics.MeterProvider
import org.typelevel.otel4s.sdk.OpenTelemetrySdk
import org.typelevel.otel4s.sdk.contrib.aws.resource._
import org.typelevel.otel4s.sdk.exporter.otlp.autoconfigure.OtlpExportersAutoConfigure
import org.typelevel.otel4s.trace.TracerProvider

object TelemetryApp extends IOApp.Simple {

def run: IO[Unit] =
OpenTelemetrySdk
.autoConfigured[IO](
// register OTLP exporters configurer
_.addExportersConfigurer(OtlpExportersAutoConfigure[IO])
// register AWS Lambda detector
.addResourceDetector(AWSLambdaDetector[IO])
)
.use { autoConfigured =>
val sdk = autoConfigured.sdk
program(sdk.meterProvider, sdk.tracerProvider)
}

def program(
meterProvider: MeterProvider[IO],
tracerProvider: TracerProvider[IO]
): IO[Unit] =
???
}
```

@:choice(traces)

`SdkTraces` configures only `TracerProvider`:

```scala mdoc:silent:reset
import cats.effect.{IO, IOApp}
import org.typelevel.otel4s.sdk.contrib.aws.resource._
import org.typelevel.otel4s.sdk.exporter.otlp.trace.autoconfigure.OtlpSpanExporterAutoConfigure
import org.typelevel.otel4s.sdk.trace.SdkTraces
import org.typelevel.otel4s.trace.TracerProvider

object TelemetryApp extends IOApp.Simple {

def run: IO[Unit] =
SdkTraces
.autoConfigured[IO](
// register OTLP exporters configurer
_.addExporterConfigurer(OtlpSpanExporterAutoConfigure[IO])
// register AWS Lambda detector
.addResourceDetector(AWSLambdaDetector[IO])
)
.use { autoConfigured =>
program(autoConfigured.tracerProvider)
}

def program(
tracerProvider: TracerProvider[IO]
): IO[Unit] =
???
}
```

@:@

## Configuration

The `OpenTelemetrySdk.autoConfigured(...)` and `SdkTraces.autoConfigured(...)` rely on the environment variables and system properties to configure the SDK.
Check out the [configuration details](configuration.md#telemetry-resource-detectors).

There are several ways to configure the options:

@:select(sdk-options-source)

@:choice(sbt)

Add settings to the `build.sbt`:

```scala
javaOptions += "-Dotel.otel4s.resource.detectors.enabled=aws-lambda"
envVars ++= Map("OTEL_OTEL4S_RESOURCE_DETECTORS_ENABLE" -> "aws-lambda")
```

@:choice(scala-cli)

Add directives to the `*.scala` file:

```scala
//> using javaOpt -Dotel.otel4s.resource.detectors.enabled=aws-lambda
```

@:choice(shell)

```shell
$ export OTEL_OTEL4S_RESOURCE_DETECTORS_ENABLED=aws-lambda
```
@:@
1 change: 1 addition & 0 deletions docs/sdk/directory.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ laika.title = SDK
laika.navigationOrder = [
overview.md
configuration.md
aws-resource-detectors.md
aws-xray-propagator.md
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2024 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.contrib.aws.resource

import cats.Monad
import cats.effect.std.Env
import cats.syntax.flatMap._
import cats.syntax.functor._
import org.typelevel.otel4s.AttributeKey
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.sdk.TelemetryResource
import org.typelevel.otel4s.sdk.resource.TelemetryResourceDetector
import org.typelevel.otel4s.semconv.SchemaUrls

private class AWSLambdaDetector[F[_]: Env: Monad]
extends TelemetryResourceDetector[F] {

import AWSLambdaDetector.Const
import AWSLambdaDetector.Keys

def name: String = Const.Name

def detect: F[Option[TelemetryResource]] =
for {
region <- Env[F].get("AWS_REGION")
functionName <- Env[F].get("AWS_LAMBDA_FUNCTION_NAME")
functionVersion <- Env[F].get("AWS_LAMBDA_FUNCTION_VERSION")
} yield build(region, functionName, functionVersion)

private def build(
region: Option[String],
functionName: Option[String],
functionVersion: Option[String]
): Option[TelemetryResource] =
Option.when(functionName.nonEmpty || functionVersion.nonEmpty) {
val builder = Attributes.newBuilder

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))

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

object AWSLambdaDetector {

private object Const {
val Name = "aws-lambda"
val CloudProvider = "aws"
val CloudPlatform = "aws_lambda"
}

private object Keys {
val CloudProvider: AttributeKey[String] = AttributeKey("cloud.provider")
val CloudPlatform: AttributeKey[String] = AttributeKey("cloud.platform")
val CloudRegion: AttributeKey[String] = AttributeKey("cloud.region")
val FaasName: AttributeKey[String] = AttributeKey("faas.name")
val FaasVersion: AttributeKey[String] = AttributeKey("faas.version")
}

/** The detector relies on the `AWS_REGION`, `AWS_LAMBDA_FUNCTION_NAME`, and
* `AWS_LAMBDA_FUNCTION_VERSION` environment variables to configure the
* telemetry resource.
*
* Either `AWS_LAMBDA_FUNCTION_NAME` or `AWS_LAMBDA_FUNCTION_VERSION` must be
* present.
*
* @example
* {{{
* OpenTelemetrySdk
* .autoConfigured[IO](
* // register OTLP exporters configurer
* _.addExportersConfigurer(OtlpExportersAutoConfigure[IO])
* // register AWS Lambda detector
* .addResourceDetector(AWSLambdaDetector[IO])
* )
* .use { autoConfigured =>
* val sdk = autoConfigured.sdk
* ???
* }
* }}}
*/
def apply[F[_]: Env: Monad]: TelemetryResourceDetector[F] =
new AWSLambdaDetector[F]

}
Loading

0 comments on commit a383be7

Please sign in to comment.