Skip to content

Commit

Permalink
Merge branch 'main' of github.com:awslabs/smithy-kotlin into feat-kmp…
Browse files Browse the repository at this point in the history
…-targets
  • Loading branch information
lauzadis committed Oct 17, 2023
2 parents d5e8009 + da00869 commit fbbc51f
Show file tree
Hide file tree
Showing 62 changed files with 954 additions and 260 deletions.
5 changes: 5 additions & 0 deletions .changes/666fa825-d13b-458c-af63-354434bfc2ed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "666fa825-d13b-458c-af63-354434bfc2ed",
"type": "feature",
"description": "Publish a BOM and a Version Catalog"
}
5 changes: 5 additions & 0 deletions .changes/6de10487-c3a0-4c63-929a-ba11a415ea8f.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "6de10487-c3a0-4c63-929a-ba11a415ea8f",
"type": "feature",
"description": "Detect and automatically correct clock skew to prevent signing errors"
}
5 changes: 5 additions & 0 deletions .changes/b31b8667-e931-49cf-8897-4e2ded2b7f14.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "b31b8667-e931-49cf-8897-4e2ded2b7f14",
"type": "misc",
"description": "Expose immutable `SpanContext` on `TraceSpan`"
}
5 changes: 5 additions & 0 deletions .changes/c063605b-4702-4d8a-a841-2e0b7aa78e78.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "c063605b-4702-4d8a-a841-2e0b7aa78e78",
"type": "misc",
"description": "**BREAKING**: Remove `smithy.client.request.size`, `smithy.client.response.size`, `smithy.client.retries` metrics. Rename all `smithy.client.*` metrics to `smithy.client.call.*`."
}
85 changes: 85 additions & 0 deletions bom/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import aws.sdk.kotlin.gradle.dsl.configurePublishing
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import java.util.*

plugins {
`maven-publish`
`java-platform`
`version-catalog`
}

val sdkVersion: String by project

group = "aws.smithy.kotlin"
version = sdkVersion

val evaluateAfter = listOf(":runtime")
evaluateAfter.forEach { evaluationDependsOn(it) }

fun createBomConstraintsAndVersionCatalog() {
val bomConstraints: DependencyConstraintHandler = dependencies.constraints
val catalogExt = catalog

project(":runtime").subprojects {
val subproject = this
val hasMavenPublish = subproject.plugins.hasPlugin("maven-publish")
if (!hasMavenPublish) {
logger.info("skipping bom and version-catalog entry for ${subproject.name}")
return@subprojects
}
subproject.plugins.withType<KotlinMultiplatformPluginWrapper> {
subproject.extensions.getByType<KotlinMultiplatformExtension>().targets.all {
val target = this
val gavCoordinates = gav(target)
bomConstraints.api(gavCoordinates)
catalogExt.versionCatalog {
val alias = artifactId(target)
library(alias, gavCoordinates)
}
}
}
}
}

fun Project.artifactId(target: KotlinTarget): String = when (target) {
is KotlinMetadataTarget -> name
is KotlinJsTarget -> "$name-js"
else -> "$name-${target.targetName.toLowerCase(Locale.ROOT)}"
}

/**
* Returns a string like "aws.sdk.kotlin:s3-linuxx64:1.0.2" for this target.
*/
fun Project.gav(target: KotlinTarget): String {
val artifactId = artifactId(target)
return "$group:$artifactId:$version"
}

fun DependencyConstraintHandler.api(constraintNotation: Any) =
add("api", constraintNotation)

createBomConstraintsAndVersionCatalog()

configurePublishing("smithy-kotlin")

publishing {
publications {
create("bom", MavenPublication::class) {
artifactId = "bom"
from(project.components.getByName("javaPlatform"))
}

create<MavenPublication>("versionCatalog") {
artifactId = "version-catalog"
from(components["versionCatalog"])
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ object RuntimeTypes {
val AwsQueryCompatibleErrorDetails = symbol("AwsQueryCompatibleErrorDetails")
val setAwsQueryCompatibleErrorMetadata = symbol("setAwsQueryCompatibleErrorMetadata")
val XAmznQueryErrorHeader = symbol("X_AMZN_QUERY_ERROR_HEADER")
val ClockSkewInterceptor = symbol("ClockSkewInterceptor")
}

object AwsJsonProtocols : RuntimeTypePackage(KotlinDependency.AWS_JSON_PROTOCOLS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ class ServiceClientGenerator(private val ctx: RenderingContext<ServiceShape>) {
*/
val RenderingContext: SectionKey<RenderingContext<ServiceShape>> = SectionKey("RenderingContext")
}

/**
* [SectionId] used when rendering the finalizeConfig block of a service client
*/
object FinalizeConfig : SectionId
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import aws.smithy.kotlin.runtime.auth.awssigning.internal.setAwsChunkedBody
import aws.smithy.kotlin.runtime.auth.awssigning.internal.setAwsChunkedHeaders
import aws.smithy.kotlin.runtime.auth.awssigning.internal.useAwsChunkedEncoding
import aws.smithy.kotlin.runtime.http.HttpBody
import aws.smithy.kotlin.runtime.http.operation.HttpOperationContext
import aws.smithy.kotlin.runtime.http.request.HttpRequest
import aws.smithy.kotlin.runtime.http.request.HttpRequestBuilder
import aws.smithy.kotlin.runtime.time.Instant
import aws.smithy.kotlin.runtime.util.get
import kotlin.time.Duration

Expand Down Expand Up @@ -123,7 +125,10 @@ public class AwsHttpSigner(private val config: Config) : HttpSigner {
service = attributes.getOrNull(AwsSigningAttributes.SigningService) ?: checkNotNull(config.service)
credentials = signingRequest.identity as Credentials
algorithm = config.algorithm

// apply clock skew if applicable
signingDate = attributes.getOrNull(AwsSigningAttributes.SigningDate)
?: (Instant.now() + (attributes.getOrNull(HttpOperationContext.ClockSkew) ?: Duration.ZERO))

signatureType = config.signatureType
omitSessionToken = config.omitSessionToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*/
package aws.smithy.kotlin.runtime.telemetry.logging.slf4j

import aws.smithy.kotlin.runtime.telemetry.context.Context
import aws.smithy.kotlin.runtime.telemetry.logging.LogLevel
import aws.smithy.kotlin.runtime.telemetry.logging.LogRecordBuilder
import aws.smithy.kotlin.runtime.telemetry.logging.LoggerProvider
Expand Down Expand Up @@ -47,10 +46,6 @@ private class Slf4j1xLogRecordBuilderAdapter(
kvp[key] = value
}

override fun setContext(context: Context) {
// TODO - add a way to get the current trace context and set the key/value pair on it?
}

override fun emit() {
val message = requireNotNull(msg) { "no message provided to LogRecordBuilder" }
val logMethod = when (level) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*/
package aws.smithy.kotlin.runtime.telemetry.logging.slf4j

import aws.smithy.kotlin.runtime.telemetry.context.Context
import aws.smithy.kotlin.runtime.telemetry.logging.LogLevel
import aws.smithy.kotlin.runtime.telemetry.logging.LogRecordBuilder
import org.slf4j.event.Level
Expand Down Expand Up @@ -37,10 +36,6 @@ private class Slf4j2xLogRecordBuilderAdapter(
delegate.addKeyValue(key, value)
}

override fun setContext(context: Context) {
// TODO - add a way to get the current trace context and set the key/value pair on it?
}

override fun emit() = delegate.log()
}

Expand Down
15 changes: 13 additions & 2 deletions runtime/observability/telemetry-api/api/telemetry-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public final class aws/smithy/kotlin/runtime/telemetry/logging/LogLevel : java/l
public abstract interface class aws/smithy/kotlin/runtime/telemetry/logging/LogRecordBuilder {
public abstract fun emit ()V
public abstract fun setCause (Ljava/lang/Throwable;)V
public abstract fun setContext (Laws/smithy/kotlin/runtime/telemetry/context/Context;)V
public abstract fun setKeyValuePair (Ljava/lang/String;Ljava/lang/Object;)V
public abstract fun setMessage (Ljava/lang/String;)V
public abstract fun setMessage (Lkotlin/jvm/functions/Function0;)V
Expand Down Expand Up @@ -191,6 +190,18 @@ public final class aws/smithy/kotlin/runtime/telemetry/metrics/UpDownCounter$Def
public final class aws/smithy/kotlin/runtime/telemetry/trace/CoroutineContextTraceExtKt {
}

public abstract interface class aws/smithy/kotlin/runtime/telemetry/trace/SpanContext {
public static final field Companion Laws/smithy/kotlin/runtime/telemetry/trace/SpanContext$Companion;
public abstract fun getSpanId ()Ljava/lang/String;
public abstract fun getTraceId ()Ljava/lang/String;
public abstract fun isRemote ()Z
public abstract fun isValid ()Z
}

public final class aws/smithy/kotlin/runtime/telemetry/trace/SpanContext$Companion {
public final fun getInvalid ()Laws/smithy/kotlin/runtime/telemetry/trace/SpanContext;
}

public final class aws/smithy/kotlin/runtime/telemetry/trace/SpanKind : java/lang/Enum {
public static final field CLIENT Laws/smithy/kotlin/runtime/telemetry/trace/SpanKind;
public static final field INTERNAL Laws/smithy/kotlin/runtime/telemetry/trace/SpanKind;
Expand All @@ -212,7 +223,7 @@ public final class aws/smithy/kotlin/runtime/telemetry/trace/SpanStatus : java/l
public abstract interface class aws/smithy/kotlin/runtime/telemetry/trace/TraceSpan : aws/smithy/kotlin/runtime/telemetry/context/Scope {
public abstract fun close ()V
public abstract fun emitEvent (Ljava/lang/String;Laws/smithy/kotlin/runtime/util/Attributes;)V
public abstract fun getName ()Ljava/lang/String;
public abstract fun getSpanContext ()Laws/smithy/kotlin/runtime/telemetry/trace/SpanContext;
public abstract fun mergeAttributes (Laws/smithy/kotlin/runtime/util/Attributes;)V
public abstract fun set (Laws/smithy/kotlin/runtime/util/AttributeKey;Ljava/lang/Object;)V
public abstract fun setStatus (Laws/smithy/kotlin/runtime/telemetry/trace/SpanStatus;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@ package aws.smithy.kotlin.runtime.telemetry.logging

import aws.smithy.kotlin.runtime.ExperimentalApi
import aws.smithy.kotlin.runtime.InternalApi
import aws.smithy.kotlin.runtime.telemetry.context.Context
import aws.smithy.kotlin.runtime.telemetry.context.telemetryContext
import aws.smithy.kotlin.runtime.telemetry.telemetryProvider
import aws.smithy.kotlin.runtime.telemetry.trace.SpanContext
import aws.smithy.kotlin.runtime.telemetry.trace.traceSpan
import kotlinx.coroutines.withContext
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext

// NOTE: these keys are specifically chosen to match the ones used by OpenTelemetry
// so that any of the javaagent/autoconfigure MDC instrumentation doesn't result in
// multiple key/value pairs with the same information.
// see: https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/v1.30.0/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/log/LoggingContextConstants.java#L14
private const val TRACE_ID_KEY = "trace_id"
private const val SPAN_ID_KEY = "span_id"

/**
* Coroutine scoped telemetry context used for carrying telemetry provider configuration
* @param kvPairs key/value pairs to add to output log statements
Expand Down Expand Up @@ -72,14 +79,17 @@ public fun CoroutineContext.log(
) {
val logger = this.telemetryProvider.loggerProvider.getOrCreateLogger(sourceComponent)
if (!logger.isEnabledFor(level)) return
val context = this.telemetryContext
val loggingContext = this.loggingContext
val spanContext = this.traceSpan?.spanContext?.takeIf(SpanContext::isValid)
logger.atLevel(level)
.apply {
ex?.let { setCause(it) }
setMessage(content)
context?.let { setContext(it) }
loggingContext.forEach { entry -> setKeyValuePair(entry.key, entry.value) }
if (spanContext != null) {
setKeyValuePair(TRACE_ID_KEY, spanContext.traceId)
setKeyValuePair(SPAN_ID_KEY, spanContext.spanId)
}
}.emit()
}

Expand Down Expand Up @@ -236,21 +246,7 @@ private class ContextAwareLogger(
override fun warn(t: Throwable?, msg: () -> String) = context.warn(sourceComponent, t, msg)
override fun error(t: Throwable?, msg: () -> String) = context.error(sourceComponent, t, msg)
override fun isEnabledFor(level: LogLevel): Boolean = delegate.isEnabledFor(level)
override fun atLevel(level: LogLevel): LogRecordBuilder {
val builder = delegate.atLevel(level)
val telemetryContext = context.telemetryContext
return telemetryContext?.let { ContextAwareLogRecordBuilder(builder, it) } ?: builder
}
}
private class ContextAwareLogRecordBuilder(
private val delegate: LogRecordBuilder,
private var context: Context,
) : LogRecordBuilder by delegate {
override fun setContext(context: Context) { this.context = context }
override fun emit() {
delegate.setContext(context)
delegate.emit()
}
override fun atLevel(level: LogLevel): LogRecordBuilder = delegate.atLevel(level)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

package aws.smithy.kotlin.runtime.telemetry.logging

import aws.smithy.kotlin.runtime.telemetry.context.Context

/**
* Construct a logging record that can be emitted to an underlying logger.
*/
Expand Down Expand Up @@ -38,12 +36,6 @@ public interface LogRecordBuilder {
*/
public fun setKeyValuePair(key: String, value: Any)

/**
* Set the telemetry context to associate with this log record
* @param context the context to associate
*/
public fun setContext(context: Context)

/**
* Emit this event to the underlying logger
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

package aws.smithy.kotlin.runtime.telemetry.logging

import aws.smithy.kotlin.runtime.telemetry.context.Context

internal object NoOpLoggerProvider : LoggerProvider {
override fun getOrCreateLogger(name: String): Logger = NoOpLogger
}
Expand All @@ -26,6 +24,5 @@ private object NoOpLogRecordBuilder : LogRecordBuilder {
override fun setMessage(message: String) {}
override fun setMessage(message: MessageSupplier) {}
override fun setKeyValuePair(key: String, value: Any) {}
override fun setContext(context: Context) {}
override fun emit() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private object NoOpTracer : Tracer {
}

private object NoOpTraceSpan : TraceSpan {
override val name: String = "NoOpSpan"
override val spanContext: SpanContext = SpanContext.Invalid
override fun emitEvent(name: String, attributes: Attributes) {}
override fun setStatus(status: SpanStatus) {}
override operator fun <T : Any> set(key: AttributeKey<T>, value: T) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.smithy.kotlin.runtime.telemetry.trace

/**
* The immutable state that must be serialized and propagated as part of a distributed trace context.
*/
public interface SpanContext {
public companion object {
public val Invalid: SpanContext = InvalidSpanContext
}

/**
* The unique trace identifier this span belongs to
*/
public val traceId: String

/**
* The unique span identifier
*/
public val spanId: String

/**
* True if the [SpanContext] was propagated from a remote parent
*/
public val isRemote: Boolean

/**
* True if the [SpanContext] has a non-zero [traceId] and [spanId]
*/
public val isValid: Boolean
}

private object InvalidSpanContext : SpanContext {
override val traceId: String = "00000000000000000000000000000000"
override val spanId: String = "0000000000000000"
override val isRemote: Boolean = false
override val isValid: Boolean = false
}
Loading

0 comments on commit fbbc51f

Please sign in to comment.